`define ysyx_040450_extern_cache_ram
// 三种环境
// YSYX22040450_ENV_ZEMU
// ysyx_040450_ENV_ysyxSoc
`ifdef YSYX22040450_DIFFTEST_FLAG // @oscpu/libraries/difftest/verilator.mk
`define ysyx_040450_PC_INITIAL           64'h00000000_7ffffffc
`define ysyx_040450_ysyxSoc_DIFF
`endif
`ifdef YSYX22040450_ENV_ZEMU
`define ysyx_040450_PC_INITIAL           64'h00000000_7ffffffc
`endif

`ifndef YSYX22040450_ENV_ZEMU
`ifndef YSYX22040450_DIFFTEST_FLAG
`define ysyx_040450_PC_INITIAL           64'h00000000_2ffffffc
`endif
`endif

`ifndef YSYX22040450_ENV_ZEMU
`define ysyx_040450_ENV_ysyxSoc
`endif
// 使用外置cache ram
// `define ysyx_040450_extern_cache_ram
// 条件触发终止仿真
// `define ysyx_040450_DBG_early_stop_fencei
// FSM解析 用于波形显示
// `define ysyx_040450_DBG_paser_FSM
// `define ysyx_040450_FPGA_IMPL
// `define ysyx_040450_OPT_MDU_SIMPLE_IMPL
// ZEMU Difftest DPI-C 接口使能
`ifdef YSYX22040450_ENV_ZEMU
    `define ysyx_040450_ZEMU_DIFF
    `define ysyx_040450_DBG_WB_BUS_WD 161 // valid pc dnpc
`endif

`ifdef ysyx_040450_ysyxSoc_DIFF
`define ysyx_040450_csr2emu_BUS_WD (9*64)
`define ysyx_040450_diff_es_BUS_WD `ysyx_040450_csr2emu_BUS_WD+1
`define ysyx_040450_diff_ms_BUS_WD `ysyx_040450_csr2emu_BUS_WD+1
`define ysyx_040450_OPT_FIT_YSYX3 // 适配三期的0x6b/0x7b指令
`endif

`define ysyx_040450_UNALIGNED_MEM

`define ysyx_040450_BR_BUS_WD       67  // br_stall 1b / irq_taken 1b / br_taken 1b / br_target 64b
`define ysyx_040450_JMP_BUS_WD      66  // jmp_stall 1b / jmp_taken 1b / jmp_target 64b
`define ysyx_040450_FS_TO_DS_BUS_WD 160 // inst 32bits / pc 64bits / snpc 64bits
`ifdef ysyx_040450_OPT_FIT_YSYX3
`define ysyx_040450_DS_TO_ES_BUS_WD 379 
`define ysyx_040450_ES_TO_MS_BUS_WD 169
`define ysyx_040450_MS_TO_WS_BUS_WD 168
`else
`define ysyx_040450_DS_TO_ES_BUS_WD 378 
`define ysyx_040450_ES_TO_MS_BUS_WD 168
`define ysyx_040450_MS_TO_WS_BUS_WD 167
`endif
`define ysyx_040450_WS_TO_RF_BUS_WD 70  // rf_we 1b / rf_waddr 5b / rf_wdata 64bit

`define ysyx_040450_ES_FWD_BUS_WD 71 // inst_LOAD 1b / rf_we 1b / rf_waddr 5b / rf_wdata 64bit
`define ysyx_040450_MS_FWD_BUS_WD 71 // rf_we 1b / rf_waddr 5b / rf_wdata 64bit

//区分不同操作可以用Funct3[2:0](3位)+Funct7[5](1位)即ALU_OP(4位)来区分
/*
    OP	  Funct3	Funct7	ALU_OP
    ADD	   000	    0000000	0000
    SUB	   000	    0100000	0001
    SLL	   001	    0000000	0010
    SLT	   010	    0000000	0100
    SLTU   011	    0000000	0110
    XOR	   100	    0000000	1000
    SRL	   101	    0000000	1010
    SRA	   101	    0100000	1011
    OR	   110	    0000000	1100
    AND	   111	    0000000	1110
*/
`define	ysyx_040450_ALU_OP_ADD  4'b0000
`define	ysyx_040450_ALU_OP_SUB  4'b0001
`define	ysyx_040450_ALU_OP_SLL  4'b0010
`define	ysyx_040450_ALU_OP_SLT  4'b0100
`define	ysyx_040450_ALU_OP_SLTU 4'b0110
`define	ysyx_040450_ALU_OP_XOR  4'b1000
`define	ysyx_040450_ALU_OP_SRL  4'b1010
`define	ysyx_040450_ALU_OP_SRA  4'b1011
`define	ysyx_040450_ALU_OP_OR   4'b1100
`define	ysyx_040450_ALU_OP_AND  4'b1110
`define	ysyx_040450_ALU_OP_IMM  4'b1111

`define	ysyx_040450_MDU_OP_MUL    4'b0000
`define	ysyx_040450_MDU_OP_MULH   4'b0010
`define	ysyx_040450_MDU_OP_MULHSU 4'b0100
`define	ysyx_040450_MDU_OP_MULHU  4'b0110
`define	ysyx_040450_MDU_OP_DIV    4'b1000
`define	ysyx_040450_MDU_OP_DIVU   4'b1010
`define	ysyx_040450_MDU_OP_REM    4'b1100
`define	ysyx_040450_MDU_OP_REMU   4'b1110
// branch logic unit
`define ysyx_040450_FUNCT3_BEQ  3'b000
`define ysyx_040450_FUNCT3_BNE  3'b001
`define ysyx_040450_FUNCT3_BLT  3'b100
`define ysyx_040450_FUNCT3_BGE  3'b101
`define ysyx_040450_FUNCT3_BLTU 3'b110
`define ysyx_040450_FUNCT3_BGEU 3'b111

`define ysyx_040450_XLEN 64
// DFF with Load-enable and Reset
module ysyx_040450_dfflr #(
  parameter WIDTH = 1, 
  parameter RESET_VAL = 0) (
    input wen,
    input [WIDTH-1:0] din,
    output reg [WIDTH-1:0] dout,
    input clk,
    input rst_n
  );
    always @(posedge clk) begin
        if (!rst_n) dout <= RESET_VAL;
        else if (wen) dout <= din;
    end
endmodule
// DFF with Reset, no load-enable
module ysyx_040450_dffr #(
  parameter WIDTH = 1, 
  parameter RESET_VAL = 0) (
    input [WIDTH-1:0] din,
    output reg [WIDTH-1:0] dout,
    input clk,
    input rst_n
  );
    always @(posedge clk) begin
        if (!rst_n) dout <= RESET_VAL;
        else dout <= din;
    end
endmodule
module ysyx_040450_decoder_3_8(
    input  [2:0] in,
    output [7:0] out
);

genvar i;
generate 
    for (i=0; i<8; i=i+1) begin : gen_for_dec_3_8
        assign out[i] = (in == i);
    end 
endgenerate

endmodule
module ysyx_040450_decoder_4_16(
    input  [ 3:0] in,
    output [15:0] out
);

genvar i;
generate 
    for (i=0; i<16; i=i+1) begin : gen_for_dec_4_16
        assign out[i] = (in == i);
    end 
endgenerate

endmodule
module ysyx_040450_decoder_5_32(
    input  [ 4:0] in,
    output [31:0] out
);

genvar i;
generate 
    for (i=0; i<32; i=i+1) begin : gen_for_dec_5_32
        assign out[i] = (in == i);
    end 
endgenerate

endmodule
module ysyx_040450_decoder_6_64(
    input  [ 5:0] in,
    output [63:0] out
);

genvar i;
generate 
    for (i=0; i<63; i=i+1) begin : gen_for_dec_6_64
        assign out[i] = (in == i);
    end 
endgenerate

endmodule
module ysyx_040450_decoder_7_128(
    input  [  6:0] in,
    output [127:0] out
);

genvar i;
generate 
    for (i=0; i<128; i=i+1) begin : gen_for_dec_7_128
        assign out[i] = (in == i);
    end 
endgenerate

endmodule
// 选择器模板内部实现
module ysyx_040450_MuxKeyInternal #(
  parameter NR_KEY = 2, 
  parameter KEY_LEN = 1, 
  parameter DATA_LEN = 1, 
  parameter HAS_DEFAULT = 0
  ) (
  output reg [DATA_LEN-1:0] out,
  input [KEY_LEN-1:0] key,
  input [DATA_LEN-1:0] default_out,
  input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);

  localparam PAIR_LEN = KEY_LEN + DATA_LEN;
  wire [PAIR_LEN-1:0] pair_list [NR_KEY-1:0];
  wire [KEY_LEN-1:0] key_list [NR_KEY-1:0];
  wire [DATA_LEN-1:0] data_list [NR_KEY-1:0];
  genvar n;
  generate
    for (n = 0; n < NR_KEY; n = n + 1) begin
      assign pair_list[n] = lut[PAIR_LEN*(n+1)-1 : PAIR_LEN*n];
      assign data_list[n] = pair_list[n][DATA_LEN-1:0];
      assign key_list[n]  = pair_list[n][PAIR_LEN-1:DATA_LEN];
    end
  endgenerate

  reg [DATA_LEN-1 : 0] lut_out;
  reg hit;
  integer i;
  always @(*) begin
    lut_out = 0;
    hit = 0;
    for (i = 0; i < NR_KEY; i = i + 1) begin
      lut_out = lut_out | ({DATA_LEN{key == key_list[i]}} & data_list[i]);
      hit = hit | (key == key_list[i]);
    end
    if (!HAS_DEFAULT) out = lut_out;
    else out = (hit ? lut_out : default_out);
  end
endmodule

// NR_KEY number key
// 不带默认值的选择器模板
module ysyx_040450_MuxKey #(
  parameter NR_KEY = 2, 
  parameter KEY_LEN = 1, 
  parameter DATA_LEN = 1
  ) (
  output [DATA_LEN-1:0] out,
  input [KEY_LEN-1:0] key,
  input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);
  ysyx_040450_MuxKeyInternal #(NR_KEY, KEY_LEN, DATA_LEN, 0) i0 (out, key, {DATA_LEN{1'b0}}, lut);
endmodule

// 带默认值的选择器模板
module ysyx_040450_MuxKeyWithDefault #(
  parameter NR_KEY = 2, 
  parameter KEY_LEN = 1, 
  parameter DATA_LEN = 1
  ) (
  output [DATA_LEN-1:0] out,
  input [KEY_LEN-1:0] key,
  input [DATA_LEN-1:0] default_out,
  input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);
  ysyx_040450_MuxKeyInternal #(NR_KEY, KEY_LEN, DATA_LEN, 1) i0 (out, key, default_out, lut);
endmodule

/*
module ysyx_040450_mux21(a,b,s,y);
  input   a,b,s;
  output  y;

  // 通过MuxKey实现如下always代码
  // always @(*) begin
  //  case (s)
  //    1'b0: y = a;
  //    1'b1: y = b;
  //  endcase
  // end
  ysyx_040450_MuxKey #(2, 1, 1) i0 (y, s, {
    1'b0, a,
    1'b1, b
  });
endmodule

module ysyx_040450_mux41(a,s,y);
  input  [3:0] a;
  input  [1:0] s;
  output y;

  // 通过MuxKeyWithDefault实现如下always代码
  // always @(*) begin
  //  case (s)
  //    2'b00: y = a[0];
  //    2'b01: y = a[1];
  //    2'b10: y = a[2];
  //    2'b11: y = a[3];
  //    default: y = 1'b0;
  //  endcase
  // end
  ysyx_040450_MuxKeyWithDefault #(4, 2, 1) i0 (y, s, 1'b0, {
    2'b00, a[0],
    2'b01, a[1],
    2'b10, a[2],
    2'b11, a[3]
  });
endmodule
*/
/*
* ysyx_040450_clint
* Base Address    0X2000000
* Bound Address   0X200BFFF
* Bytes reserved  0XBFFF
*/
module ysyx_040450_clint(
    // data bus
    // input         clint_ena  ,
    input         clint_wr_en,
    input         clint_rd_en,
    input  [15:0] clint_idx  ,
    input  [63:0] clint_wdata,
    output [63:0] clint_rdata,

    // irq out
    output clint_sft_irq,
    output clint_tmr_irq,

    input clk,
    input rst_n
);
// wire timer_cnt_clk;
wire [63:0] rdata;

////////////////////////////////////////////////////
//0x0200_0000 MRW msip
// ysyx_040450_dfflr #(32) clint_msip_dfflr (status_mpie_ena, status_mpie_nxt, status_mpie_r, clk, rst_n);

////////////////////////////////////////////////////
//0x0200_4000 MRW mtimecmp
wire [63:0] mtimecmp_r;
wire sel_mtimecmp = (clint_idx==16'h4000);
wire rd_mtimecmp = sel_mtimecmp & clint_rd_en;
wire wr_mtimecmp = sel_mtimecmp & clint_wr_en;
wire mtimecmp_ena = wr_mtimecmp;
ysyx_040450_dfflr #(64, 64'hffff_ffff_ffff_ffff) clint_mtimecmp_dfflr (mtimecmp_ena, clint_wdata, mtimecmp_r, clk, rst_n);

////////////////////////////////////////////////////
//0x0200_BFF8 MRW mtime
wire [63:0] mtime_r;
wire sel_mtime = (clint_idx==16'hBFF8);
wire rd_mtime = sel_mtime & clint_rd_en;
wire wr_mtime = sel_mtime & clint_wr_en;
wire mtime_ena = 1'b1;//wr_mtime;
wire [63:0] mtime_nxt = wr_mtime ? clint_wdata : mtime_r+64'd1;
ysyx_040450_dfflr #(64) clint_mtime_dfflr (mtime_ena, mtime_nxt, mtime_r, clk, rst_n);

assign rdata = 64'b0 
               | ({64{rd_mtimecmp }} & mtimecmp_r )
               | ({64{rd_mtime    }} & mtime_r    )
               ;
// 打一拍输出
ysyx_040450_dffr #(64) clint_rdata_dffr (rdata, clint_rdata, clk, rst_n);

assign clint_sft_irq = 1'b0; // 未实现软件中断
assign clint_tmr_irq = mtime_r >= mtimecmp_r;

endmodule

module ysyx_040450_clint_wrap(
    input         clint_data_req    ,
    input         clint_data_wr     ,
    input  [1 :0] clint_data_size   ,
    input  [7 :0] clint_data_wstrb  ,
    input  [63:0] clint_data_addr   ,
    input  [63:0] clint_data_wdata  ,
    output        clint_data_addr_ok,
    output        clint_data_data_ok,
    output [63:0] clint_data_rdata  ,

    // irq out
    output clint_sft_irq,
    output clint_tmr_irq,

    input clk  ,
    input rst_n
);
// data bus
wire        clint_ena  ;
wire        clint_wr_en;
wire        clint_rd_en;
wire [15:0] clint_idx  ;
wire [63:0] clint_wdata;
wire [63:0] clint_rdata;

///////////////////////////////////////
// 
assign clint_data_addr_ok = 1'b1;
// 打一拍返回数据
ysyx_040450_dffr #(1) clint_wrap_dataok_dffr (clint_ena, clint_data_data_ok, clk, rst_n);
assign clint_data_rdata = clint_rdata;

///////////////////////////////////////
// 
assign clint_ena   = clint_data_req & clint_data_addr_ok;
assign clint_wr_en = clint_data_req &  clint_data_wr;
assign clint_rd_en = clint_data_req & !clint_data_wr;
assign clint_idx   = clint_data_addr[15:0];
assign clint_wdata = clint_data_wdata;

ysyx_040450_clint u_clint(
// .clint_ena  (clint_ena  ),
.clint_wr_en(clint_wr_en),
.clint_rd_en(clint_rd_en),
.clint_idx  (clint_idx  ),
.clint_wdata(clint_wdata),
.clint_rdata(clint_rdata),
.clint_sft_irq(clint_sft_irq),
.clint_tmr_irq(clint_tmr_irq),
.clk  (clk  ),
.rst_n(rst_n)
);

endmodule

// 读写受csr_ctrl模块控制
// 同时直接暴露部分接口到exe模块用于控制 e.g. epc
module ysyx_040450_csr (
  // from csr_ctrl
  input csr_ena,
  input csr_wr_en,
  input csr_rd_en,
  input [12-1:0] csr_idx,

  output [`ysyx_040450_XLEN-1:0] read_csr_dat,
  input  [`ysyx_040450_XLEN-1:0] wbck_csr_dat,

  // mcause 计算
  // output u_mode,
  // output s_mode,
  // output h_mode,
  // output m_mode,

  // irq req
  input               plic_ext_irq,
  input               clint_sft_irq,
  input               clint_tmr_irq,

  output csr_status_MIE_r,
  output csr_mie_MEIE_r  ,
  output csr_mie_MTIE_r  ,
  output csr_mie_MSIE_r  ,

  // to es
  // 需要单独读写的寄存器 ecall
  input [`ysyx_040450_XLEN-1:0]   cmt_epc      ,
  input               cmt_epc_ena  ,
  input [`ysyx_040450_XLEN-1:0]   cmt_cause    ,
  input               cmt_cause_ena,
  input               cmt_instret_ena,
  // mepc / mtvec
  output[`ysyx_040450_XLEN-1:0]   csr_epc_r    ,
  output[`ysyx_040450_XLEN-1:0]   csr_mtvec_r  ,

  input               cmt_status_ena, // excp/irq token
  input               cmt_mret_ena  , // excp/irq exit/done

  `ifdef ysyx_040450_ysyxSoc_DIFF
  output [`ysyx_040450_csr2emu_BUS_WD-1:0] csr2emu_bus,
  `endif

  input clk,
  input rst_n
);

// Only toggle when need to read or write to save power
wire wbck_csr_wen = csr_wr_en & csr_ena;
// wire read_csr_ena = csr_rd_en & csr_ena;
//////////////////////////////////////////////////////////////////////

//0x300 MRW mstatus Machine status register.
wire sel_mstatus = (csr_idx == 12'h300);

wire rd_mstatus = sel_mstatus & csr_rd_en;
wire wr_mstatus = sel_mstatus & csr_wr_en;

//////////////////////////
wire [1:0] status_XS_r;
wire [1:0] status_FS_r;
wire [1:0] status_MPP_r;
wire status_MPIE_r;
wire status_MIE_r;
//////////////////////////
// Implement mstatus XS field
//
// FIXME 实际不支持，为了适配difftest增加此寄存器
wire status_XS_ena = wr_mstatus & wbck_csr_wen;
wire [1:0] status_XS_nxt = wbck_csr_dat[16:15]; 
ysyx_040450_dfflr #(2) status_XS_dfflr (status_XS_ena, status_XS_nxt, status_XS_r, clk, rst_n);

//////////////////////////
// Implement mstatus FS field
//
// FIXME 实际不支持，为了适配difftest增加此寄存器
wire status_FS_ena = wr_mstatus & wbck_csr_wen;
wire [1:0] status_FS_nxt = wbck_csr_dat[14:13]; 
ysyx_040450_dfflr #(2) status_FS_dfflr (status_FS_ena, status_FS_nxt, status_FS_r, clk, rst_n);

//////////////////////////
// Implement mstatus MPP field
//
// FIXME 实际不支持S-mode，为了适配difftest增加此寄存器
// The MPP Feilds will be updates when: 
wire status_MPP_ena  = 
    // The CSR is written by CSR instructions
    (wr_mstatus & wbck_csr_wen) |
    // The MRET instruction commited
    cmt_mret_ena |
    // The Trap is taken
    cmt_status_ena;

wire [1:0] status_MPP_nxt    = 
  cmt_status_ena ? 2'b11 :
  cmt_mret_ena  ? 2'b00 :
  (wr_mstatus & wbck_csr_wen) ? wbck_csr_dat[12:11] : // MPIE is in field 7 of mstatus
              status_MPP_r; // Unchanged 

ysyx_040450_dfflr #(2,2'b11) status_mpp_dfflr (status_MPP_ena, status_MPP_nxt, status_MPP_r, clk, rst_n);


//////////////////////////
// Implement mstatus MPIE field
//
    // The MPIE Feilds will be updates when: 
wire status_MPIE_ena  = 
        // The CSR is written by CSR instructions
        (wr_mstatus & wbck_csr_wen) |
        // The MRET instruction commited
        cmt_mret_ena |
        // The Trap is taken
        cmt_status_ena;

wire status_MPIE_nxt    = 
    //   See Priv SPEC:
    //       When a trap is taken from privilege mode y into privilege
    //       mode x, xPIE is set to the value of xIE;
    // So, When the Trap is taken, the MPIE is updated with the current MIE value
    cmt_status_ena ? status_MIE_r :
    //   See Priv SPEC:
    //       When executing an xRET instruction, supposing xPP holds the value y, xIE
    //       is set to xPIE; the privilege mode is changed to y; 
    //       xPIE is set to 1;
    // So, When the MRET instruction commited, the MPIE is updated with 1
    cmt_mret_ena  ? 1'b1 :
    // When the CSR is written by CSR instructions
    (wr_mstatus & wbck_csr_wen) ? wbck_csr_dat[7] : // MPIE is in field 7 of mstatus
                  status_MPIE_r; // Unchanged 

ysyx_040450_dfflr #(1) status_mpie_dfflr (status_MPIE_ena, status_MPIE_nxt, status_MPIE_r, clk, rst_n);

//////////////////////////
// Implement mstatus MIE field
//
    // The MIE Feilds will be updates same as MPIE
wire status_MIE_ena  = status_MPIE_ena; 
wire status_MIE_nxt    = 
    //   See Priv SPEC:
    //       When a trap is taken from privilege mode y into privilege
    //       mode x, xPIE is set to the value of xIE,
    //       xIE is set to 0;
    // So, When the Trap is taken, the MIE is updated with 0
     cmt_status_ena ? 1'b0 :
    //   See Priv SPEC:
    //       When executing an xRET instruction, supposing xPP holds the value y, xIE
    //       is set to xPIE; the privilege mode is changed to y, xPIE is set to 1;
    // So, When the MRET instruction commited, the MIE is updated with MPIE
    cmt_mret_ena ? status_MPIE_r :
    // When the CSR is written by CSR instructions
    (wr_mstatus & wbck_csr_wen) ? wbck_csr_dat[3] : // MIE is in field 3 of mstatus
                  status_MIE_r; // Unchanged 

ysyx_040450_dfflr #(1) status_MIE_dfflr (status_MIE_ena, status_MIE_nxt, status_MIE_r, clk, rst_n);

assign csr_status_MIE_r = status_MIE_r;
////////////////////////////////////////////////////
// Pack to the full mstatus register
//
wire [`ysyx_040450_XLEN-1:0] status_r;
assign status_r[63]    = (&status_XS_r)|(&status_FS_r);//1'b0;//status_sd_r;                        //SD
assign status_r[62:38] = 25'h0; // Reserved
assign status_r[37]    = 1'b0;               // MBE
assign status_r[36]    = 1'b0;               // SBE
assign status_r[35:34] = 2'b00;              // SXL S-Mode XLEN (assign to zero if not support S-Mode)
assign status_r[33:32] = 2'b00;              // UXL U-Mode XLEN (assign to zero if not support U-Mode)
assign status_r[31:23] = 9'b0; // Reserved
assign status_r[22:17] = 6'b0;               // TSR--MPRV
assign status_r[16:15] = status_XS_r;//2'b00;//status_xs_r;                        // XS
assign status_r[14:13] = status_FS_r;//2'b00;//status_fs_r;                        // FS
assign status_r[12:11] = status_MPP_r;//2'b11;              // MPP - Previous Privilege
assign status_r[10:9]  = 2'b0; // Reserved
assign status_r[8]     = 1'b0;               // SPP
assign status_r[7]     = status_MPIE_r;                      // MPIE
assign status_r[6]     = 1'b0;               // UBE
assign status_r[5]     = 1'b0;               // SPIE 
assign status_r[4]     = 1'b0; // Reserved UPIE
assign status_r[3]     = status_MIE_r;                       // MIE
assign status_r[2]     = 1'b0; // Reserved
assign status_r[1]     = 1'b0;               // SIE 
assign status_r[0]     = 1'b0; // Reserved UIE

// assign status_r[4]     = 1'b0;               // UPIE 
// assign status_r[0]     = 1'b0;               // UIE 
wire [`ysyx_040450_XLEN-1:0] csr_mstatus = status_r;

////////////////////////////////////////////////////
//0x304 MRW mie Machine interrupt-enable register.
wire sel_mie = (csr_idx == 12'h304);
wire rd_mie = sel_mie & csr_rd_en;
wire wr_mie = sel_mie & csr_wr_en;
wire mie_ena = wr_mie & wbck_csr_wen;
wire [`ysyx_040450_XLEN-1:0] mie_r;
wire [`ysyx_040450_XLEN-1:0] mie_nxt;
assign mie_nxt[63:32] = 32'b0;
assign mie_nxt[31:12] = 20'b0;
assign mie_nxt[11] = wbck_csr_dat[11];//MEIE
assign mie_nxt[10:8] = 3'b0;
assign mie_nxt[ 7] = wbck_csr_dat[ 7];//MTIE
assign mie_nxt[6:4] = 3'b0;
assign mie_nxt[ 3] = wbck_csr_dat[ 3];//MSIE
assign mie_nxt[2:0] = 3'b0;
ysyx_040450_dfflr #(`ysyx_040450_XLEN) mie_dfflr (mie_ena, mie_nxt, mie_r, clk, rst_n);
wire [`ysyx_040450_XLEN-1:0] csr_mie = mie_r;

assign csr_mie_MEIE_r = csr_mie[11];
assign csr_mie_MTIE_r = csr_mie[ 7];
assign csr_mie_MSIE_r = csr_mie[ 3];

////////////////////////////////////////////////////
//0x344 MRW mip Machine interrupt pending
wire sel_mip = (csr_idx == 12'h344);
wire rd_mip = sel_mip & csr_rd_en;
//wire wr_mip = sel_mip & csr_wr_en;
// The MxIP is read-only
wire meip_r;
wire msip_r;
wire mtip_r;
ysyx_040450_dffr #(1) meip_dffr (plic_ext_irq , meip_r, clk, rst_n);
ysyx_040450_dffr #(1) msip_dffr (clint_sft_irq, msip_r, clk, rst_n);
ysyx_040450_dffr #(1) mtip_dffr (clint_tmr_irq, mtip_r, clk, rst_n);

wire [`ysyx_040450_XLEN-1:0] ip_r;
assign ip_r[63:32] = 32'b0;
assign ip_r[31:12] = 20'b0;
assign ip_r[11] = meip_r;
assign ip_r[10:8] = 3'b0;
assign ip_r[ 7] = mtip_r;
assign ip_r[6:4] = 3'b0;
assign ip_r[ 3] = msip_r;
assign ip_r[2:0] = 3'b0;
wire [`ysyx_040450_XLEN-1:0] csr_mip = ip_r;

////////////////////////////////////////////////////
//0x305 MRW mtvec Machine trap-handler base address.
wire sel_mtvec = (csr_idx == 12'h305);
wire rd_mtvec = csr_rd_en & sel_mtvec;
wire wr_mtvec = sel_mtvec & csr_wr_en;
wire mtvec_ena = (wr_mtvec & wbck_csr_wen);
wire [`ysyx_040450_XLEN-1:0] mtvec_r;
wire [`ysyx_040450_XLEN-1:0] mtvec_nxt = wbck_csr_dat;
ysyx_040450_dfflr  #(`ysyx_040450_XLEN, 0) mtvec_dfflr (mtvec_ena, mtvec_nxt, mtvec_r, clk, rst_n);
wire [`ysyx_040450_XLEN-1:0] csr_mtvec = mtvec_r;
assign csr_mtvec_r = csr_mtvec;

////////////////////////////////////////////////////
//0x340 MRW mscratch 
wire sel_mscratch = (csr_idx == 12'h340);
wire rd_mscratch = sel_mscratch & csr_rd_en;
wire wr_mscratch = sel_mscratch & csr_wr_en;
wire mscratch_ena = (wr_mscratch & wbck_csr_wen);
wire [`ysyx_040450_XLEN-1:0] mscratch_r;
wire [`ysyx_040450_XLEN-1:0] mscratch_nxt = wbck_csr_dat;
ysyx_040450_dfflr #(`ysyx_040450_XLEN) mscratch_dfflr (mscratch_ena, mscratch_nxt, mscratch_r, clk, rst_n);
wire [`ysyx_040450_XLEN-1:0] csr_mscratch = mscratch_r;

////////////////////////////////////////////////////
// 0xB00 MRW mcycle 
// 0xB02 MRW minstret 
wire sel_mcycle    = (csr_idx == 12'hB00);
wire sel_minstret  = (csr_idx == 12'hB02);
wire rd_mcycle     = csr_rd_en & sel_mcycle   ;
wire rd_minstret   = csr_rd_en & sel_minstret ;
wire wr_mcycle     = csr_wr_en & sel_mcycle   ;
wire wr_minstret   = csr_wr_en & sel_minstret ;
wire mcycle_wr_ena    = (wr_mcycle    & wbck_csr_wen);
wire minstret_wr_ena  = (wr_minstret  & wbck_csr_wen);
wire mcycle_ena    = /*mcycle_wr_ena   |*/ 1'b1;
wire minstret_ena  = minstret_wr_ena | cmt_instret_ena;
wire [`ysyx_040450_XLEN-1:0] mcycle_r   ;
wire [`ysyx_040450_XLEN-1:0] minstret_r ;
wire [`ysyx_040450_XLEN-1:0] mcycle_nxt    = mcycle_wr_ena    ? wbck_csr_dat : (mcycle_r    + 1'b1);
wire [`ysyx_040450_XLEN-1:0] minstret_nxt  = minstret_wr_ena  ? wbck_csr_dat : (minstret_r  + 1'b1);
ysyx_040450_dfflr #(`ysyx_040450_XLEN) mcycle_dfflr (mcycle_ena, mcycle_nxt, mcycle_r   , clk, rst_n);
ysyx_040450_dfflr #(`ysyx_040450_XLEN) minstret_dfflr (minstret_ena, minstret_nxt, minstret_r , clk, rst_n);

wire [`ysyx_040450_XLEN-1:0] csr_mcycle    = mcycle_r;
wire [`ysyx_040450_XLEN-1:0] csr_minstret  = minstret_r;

////////////////////////////////////////////////////
//0x041 URW uepc User exception program counter.
//  We dont support user trap, so no uepc needed
//0x341 MRW mepc Machine exception program counter.
wire sel_mepc = (csr_idx == 12'h341);
wire rd_mepc = sel_mepc & csr_rd_en;
wire wr_mepc = sel_mepc & csr_wr_en;
wire epc_ena = (wr_mepc & wbck_csr_wen) | cmt_epc_ena;
wire [`ysyx_040450_XLEN-1:0] epc_r;
wire [`ysyx_040450_XLEN-1:0] epc_nxt;
assign epc_nxt[`ysyx_040450_XLEN-1:1] = cmt_epc_ena ? cmt_epc[`ysyx_040450_XLEN-1:1] : wbck_csr_dat[`ysyx_040450_XLEN-1:1];
assign epc_nxt[0] = 1'b0;// Must not hold PC which will generate the misalign exception according to ISA
ysyx_040450_dfflr  #(`ysyx_040450_XLEN, 0) epc_dfflr (epc_ena, epc_nxt, epc_r, clk, rst_n);
wire [`ysyx_040450_XLEN-1:0] csr_mepc;
assign csr_mepc = epc_r;
assign csr_epc_r = csr_mepc;

////////////////////////////////////////////////////
//0x042 URW ucause User trap cause.
//  We dont support user trap, so no ucause needed
//0x342 MRW mcause Machine trap cause.
wire sel_mcause = (csr_idx == 12'h342);
wire rd_mcause = sel_mcause & csr_rd_en;
wire wr_mcause = sel_mcause & csr_wr_en;
wire cause_ena = (wr_mcause & wbck_csr_wen) | cmt_cause_ena;
wire [`ysyx_040450_XLEN-1:0] cause_r;
wire [`ysyx_040450_XLEN-1:0] cause_nxt;
assign cause_nxt = cmt_cause_ena ? cmt_cause : wbck_csr_dat;
ysyx_040450_dfflr  #(`ysyx_040450_XLEN, 0) cause_dfflr (cause_ena, cause_nxt, cause_r, clk, rst_n);
wire [`ysyx_040450_XLEN-1:0] csr_mcause = cause_r;

////////////////////////////////////////////////////
//0x301 MRW misa ISA and extensions
wire sel_misa = (csr_idx == 12'h301);
wire rd_misa = sel_misa & csr_rd_en;
// Only implemented the M mode, IMC or EMC
wire [`ysyx_040450_XLEN-1:0] csr_misa = {2'b10,{`ysyx_040450_XLEN-28{1'b0}},26'h1100}; //RV64IM

/////////////////////////////////////////////////////////////////////
//Machine Information Registers
//0xF11 MRO mvendorid Vendor ID.
//0xF12 MRO marchid Architecture ID.
//0xF13 MRO mimpid Implementation ID.
//0xF14 MRO mhartid Hardware thread ID.
wire [`ysyx_040450_XLEN-1:0] csr_mvendorid = `ysyx_040450_XLEN'h7a68436f7265; // zhCore
wire [`ysyx_040450_XLEN-1:0] csr_marchid   = `ysyx_040450_XLEN'h7973797834; // ysyx4
wire [`ysyx_040450_XLEN-1:0] csr_mimpid    = `ysyx_040450_XLEN'h1;
wire [`ysyx_040450_XLEN-1:0] csr_mhartid   = `ysyx_040450_XLEN'h0;
wire rd_mvendorid = csr_rd_en & (csr_idx == 12'hF11);
wire rd_marchid   = csr_rd_en & (csr_idx == 12'hF12);
wire rd_mimpid    = csr_rd_en & (csr_idx == 12'hF13);
wire rd_mhartid   = csr_rd_en & (csr_idx == 12'hF14);

/////////////////////////////////////////////////////////////////////
//  Generate the Read path
  //Currently we only support the M mode to simplify the implementation and 
  //      reduce the gatecount because we are a privite core
// assign u_mode = 1'b0;
// assign s_mode = 1'b0;
// assign h_mode = 1'b0;
// assign m_mode = 1'b1;
assign read_csr_dat = `ysyx_040450_XLEN'b0 
               | ({`ysyx_040450_XLEN{rd_mstatus  }} & csr_mstatus  )
               | ({`ysyx_040450_XLEN{rd_mie      }} & csr_mie      )
               | ({`ysyx_040450_XLEN{rd_mip      }} & csr_mip      )
               | ({`ysyx_040450_XLEN{rd_mtvec    }} & csr_mtvec    )
               | ({`ysyx_040450_XLEN{rd_mscratch }} & csr_mscratch )
               | ({`ysyx_040450_XLEN{rd_mcycle   }} & csr_mcycle   )
               | ({`ysyx_040450_XLEN{rd_minstret }} & csr_minstret )
               | ({`ysyx_040450_XLEN{rd_mepc     }} & csr_mepc     )
               | ({`ysyx_040450_XLEN{rd_mcause   }} & csr_mcause   )
               | ({`ysyx_040450_XLEN{rd_misa     }} & csr_misa     )
               | ({`ysyx_040450_XLEN{rd_mvendorid}} & csr_mvendorid)
               | ({`ysyx_040450_XLEN{rd_marchid  }} & csr_marchid  )
               | ({`ysyx_040450_XLEN{rd_mimpid   }} & csr_mimpid   )
               | ({`ysyx_040450_XLEN{rd_mhartid  }} & csr_mhartid  )
               ;

`ifdef ysyx_040450_ysyxSoc_DIFF
wire [63:0] diff_mstatus;
wire [1:0] diff_mstatus_XS = status_XS_ena ? status_XS_nxt : status_XS_r;
wire [1:0] diff_mstatus_FS = status_FS_ena ? status_FS_nxt : status_FS_r;
assign diff_mstatus[63] = (&diff_mstatus_XS)|(&diff_mstatus_FS);
assign diff_mstatus[62:17] = csr_mstatus[62:17];
assign diff_mstatus[16:15] = diff_mstatus_XS;
assign diff_mstatus[14:13] = diff_mstatus_FS;
assign diff_mstatus[12:11] = status_MPP_ena ? status_MPP_nxt : status_MPP_r;
assign diff_mstatus[10:8] = csr_mstatus[10:8];
assign diff_mstatus[7] = status_MPIE_ena ? status_MPIE_nxt : status_MPIE_r;
assign diff_mstatus[6:4] = csr_mstatus[6:4];
assign diff_mstatus[3] = status_MIE_ena ? status_MIE_nxt : status_MIE_r;
assign diff_mstatus[2:0] = csr_mstatus[2:0];
assign csr2emu_bus = {
  mcycle_nxt  ,
  minstret_nxt,
  diff_mstatus,
  epc_ena      ? epc_nxt      : csr_mepc    ,
  mtvec_ena    ? mtvec_nxt    : csr_mtvec   ,
  mscratch_ena ? mscratch_nxt : csr_mscratch,
  cause_ena    ? cause_nxt    : csr_mcause  ,
  csr_mip     , //unused
  mie_ena      ? mie_nxt      : csr_mie     
};
`endif
endmodule


/*
wire [`ysyx_040450_XLEN-1:0] csr_misa = {
    2'b10 // MXL 1:XLEN=32 2:XLEN=64 3:XLEN=128
   ,36'b0 //WIRI MXLEN-28
   ,1'b0 //              25 Z Reserved
   ,1'b0 //              24 Y Reserved
   ,1'b0 //              23 X Non-standard extensions present
   ,1'b0 //              22 W Reserved
   ,1'b0 //              21 V Tentatively reserved for Vector extension 20 U User mode implemented
   ,1'b0 //              20 U User mode implemented
   ,1'b0 //              19 T Tentatively reserved for Transactional Memory extension
   ,1'b0 //              18 S Supervisor mode implemented
   ,1'b0 //              17 R Reserved
   ,1'b0 //              16 Q Quad-precision floating-point extension
   ,1'b0 //              15 P Tentatively reserved for Packed-SIMD extension
   ,1'b0 //              14 O Reserved
   ,1'b0 //              13 N User-level interrupts supported
   ,1'b1 // 12 M Integer Multiply/Divide extension
   ,1'b0 //              11 L Tentatively reserved for Decimal Floating-Point extension
   ,1'b0 //              10 K Reserved
   ,1'b0 //              9 J Reserved
   ,1'b1 // 8 I RV32I/64I/128I base ISA
   ,1'b0 //              7 H Hypervisor mode implemented
   ,1'b0 //              6 G Additional standard extensions present
   ,1'b0 //              5 F Single-precision floating-point extension
   ,1'b0 //              4 E RV32E base ISA
   ,1'b0 //              3 D Double-precision floating-point extension
   ,1'b0 //              2 C Compressed extension
   ,1'b0 //              1 B Tentatively reserved for Bit operations extension
   ,1'b0 //              0 A Atomic extension
                           };
*/

// 接收来自exe阶段的指令和rs1_data，解码指令实现csr的读写
// 得到读取数据csr_o_wbck_wdat用于写回rf
module ysyx_040450_csr_ctrl(

  //////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////
  // to csr
  //
  input  csr_i_valid, // Handshake valid
  // output csr_i_ready, // Handshake ready

  input  [`ysyx_040450_XLEN-1:0] rs1_data,
  input  [31:0] inst,
  input  csr_i_rdwen,   

  output csr_ena,
  output csr_wr_en,
  output csr_rd_en,
  output [12-1:0] csr_idx,

  input  [`ysyx_040450_XLEN-1:0] read_csr_dat,
  output [`ysyx_040450_XLEN-1:0] wbck_csr_dat,

  //////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////
  // to exe
  // output csr_o_valid, // Handshake valid
  // input  csr_o_ready, // Handshake ready
  //   The Write-Back Interface for Special (unaligned ldst and AMO instructions) 
  output [`ysyx_040450_XLEN-1:0] csr_o_wbck_wdat

  // input  clk,
  // input  rst_n
  );

  // assign csr_o_valid      = csr_i_valid;
  // assign csr_i_ready      = csr_o_ready;
  assign csr_o_wbck_wdat  = read_csr_dat;

  wire        csrrw  = inst[13:12]==2'b01; // funct3[1:0]
  wire        csrrs  = inst[13:12]==2'b10;
  wire        csrrc  = inst[13:12]==2'b11;
  wire        rs1imm = inst[14]; // funct3[2]
  wire        rs1is0 = inst[19:15] == 5'h00;
  wire [4:0]  zimm   = inst[19:15];
  wire [11:0] csridx = inst[31:20];

  wire [`ysyx_040450_XLEN-1:0] csr_op1 = rs1imm ? {59'b0,zimm} : rs1_data;

  assign csr_rd_en = csr_i_valid & 
    (
      (csrrw ? csr_i_rdwen : 1'b0) // the CSRRW only read when the destination reg need to be writen
      | csrrs | csrrc // The set and clear operation always need to read CSR
     );
  assign csr_wr_en = csr_i_valid & (
                csrrw // CSRRW always write the original RS1 value into the CSR
               | ((csrrs | csrrc) & (~rs1is0)) // for CSRRS/RC, if the RS is x0, then should not really write                                        
            );                                                                           
                                                                                         
  assign csr_idx = csridx;

  assign csr_ena = csr_i_valid;//csr_o_valid;// & csr_o_ready;

  assign wbck_csr_dat = 
              ({`ysyx_040450_XLEN{csrrw}} & csr_op1)
            | ({`ysyx_040450_XLEN{csrrs}} & (  csr_op1  | read_csr_dat))
            | ({`ysyx_040450_XLEN{csrrc}} & ((~csr_op1) & read_csr_dat));

endmodule
// branch logic unit
module ysyx_040450_blu(
    input           [63:0]  in_a,
    input           [63:0]  in_b,
    input            [2:0]  funct3,
    output reg            result
);

always @(*) begin
    case(funct3)
        `ysyx_040450_FUNCT3_BEQ:    result = in_a == in_b;
        `ysyx_040450_FUNCT3_BNE:    result = in_a != in_b;
        `ysyx_040450_FUNCT3_BLT:    result = $signed(in_a) < $signed(in_b);
        `ysyx_040450_FUNCT3_BGE:    result = $signed(in_a) >= $signed(in_b);
        `ysyx_040450_FUNCT3_BLTU:   result = in_a < in_b;
        `ysyx_040450_FUNCT3_BGEU:   result = in_a >= in_b;
        default:        result = 0;
    endcase
end
endmodule
module ysyx_040450_regfile #(parameter ADDR_WIDTH = 5, parameter DATA_WIDTH = 64) (
    input clk,
    `ifdef ysyx_040450_ysyxSoc_DIFF
	output wire [63:0] rf_regs[0 : 31],
    `endif
    input [DATA_WIDTH-1:0] wdata,
    input [ADDR_WIDTH-1:0] waddr,
    input wen,
    input [ADDR_WIDTH-1:0] raddr_a,
    input [ADDR_WIDTH-1:0] raddr_b,
    output [DATA_WIDTH-1:0] rdata_a,
    output [DATA_WIDTH-1:0] rdata_b
);

reg [DATA_WIDTH-1:0] rf [32-1:0];
always @(posedge clk) begin
    if (wen) rf[waddr] <= wdata;
end

assign rdata_a = (raddr_a == 0) ? {DATA_WIDTH{1'b0}} : rf[raddr_a];
assign rdata_b = (raddr_b == 0) ? {DATA_WIDTH{1'b0}} : rf[raddr_b];
// assign rdata_a = rf[raddr_a];
// assign rdata_b = rf[raddr_b];

`ifdef ysyx_040450_ZEMU_DIFF
import "DPI-C" function void set_gpr_ptr(input logic [63:0] a []);
initial set_gpr_ptr(rf);  // rf为通用寄存器的二维数组变量
// import "DPI-C" function void v_difftest_ArchIntRegState();
`endif

`ifdef ysyx_040450_ysyxSoc_DIFF
assign rf_regs[0] = 64'd0;
genvar i;
generate
    for (i = 1; i < 32; i = i + 1) begin
        assign rf_regs[i] = (wen & waddr == i & i != 0) ? wdata : rf[i];
    end
endgenerate
`endif

endmodule

module ysyx_040450_multiplier #(parameter WIDTH=16) (
    input                mult_valid_i,
    output               mult_valid_o,
    output               mult_ready_o, // unconditional ready

    input                signed_a_i  ,
    input                signed_b_i  ,
    input                is_half_op_i,
    input  [WIDTH-1:0]   operand_a_i ,
    input  [WIDTH-1:0]   operand_b_i ,
    output [2*WIDTH-1:0] result_o    ,

    input clk,
    input resetn
);

wire [6:0] cnt_num = is_half_op_i ? WIDTH/4+1+1 : WIDTH/2+1+1;
reg is_half_op_r;
wire is_half_op = mult_valid_i ? is_half_op_i : is_half_op_r;
always @(posedge clk) begin
    if(!resetn) is_half_op_r <= 1'b0;
    else if(mult_valid_i) is_half_op_r <= is_half_op_i;
end

// cnt
reg [6:0] counter; // TODO 寄存器宽度参数化
always @(posedge clk) begin
    if(!resetn) counter <= 7'b0;
    else if(mult_valid_i) counter <= cnt_num;
    else if (|counter) begin
        counter <= counter - 1'b1;
    end
end

assign mult_valid_o = (counter==1);
assign mult_ready_o = ~|counter;

wire sext_a = signed_a_i ? operand_a_i[WIDTH/2-1] : 1'b0;
wire sext_b = signed_b_i ? operand_b_i[WIDTH/2-1] : 1'b0;
reg [WIDTH+1:0] operand_a_r; // 需要符号扩展 {Sign,Sign,operand_a_in}
reg [WIDTH+2:0] operand_b_r; // 一周期左移 {Sign,Sign,operand_b_in,0}
wire [WIDTH+1:0] next_operand_a = is_half_op ? {{WIDTH/2+2{sext_a}}, operand_a_i[WIDTH/2-1:0]} :
                                                {{2{sext_a}}, operand_a_i};
wire [WIDTH+2:0] next_operand_b = is_half_op ? {{WIDTH/2{1'b0}}, {2{sext_b}}, operand_b_i[WIDTH/2-1:0], 1'b0} :
                                                {{2{sext_b}}, operand_b_i, 1'b0};
always @(posedge clk) begin
	if(!resetn) operand_a_r <= {WIDTH+2{1'b0}};
    else if(mult_valid_i) begin
		operand_a_r <= next_operand_a;
	end
end
always @(posedge clk) begin
	if(!resetn) operand_b_r <= {WIDTH+3{1'b0}};
    else if(mult_valid_i) begin
		operand_b_r <= next_operand_b;
	end else begin // TODO 非工作时不跳变
        // 每周期左移2位以给出正确的booth code
		operand_b_r <= {operand_b_r[WIDTH:0], 2'b00};
	end
end
// booth code 指向固定区间
wire [2:0] code = is_half_op ? operand_b_r[WIDTH/2+2:WIDTH/2] :
                            operand_b_r[WIDTH+2:WIDTH];
wire neg, zero, one, two;
wire [2*(WIDTH+2)-1:0] prod;
reg  [2*(WIDTH+2)-1:0] mul_result;

ysyx_040450_booth_enc u_booth_enc(
	.code (code),
	.neg  (neg),
	.zero (zero),
	.one  (one),
	.two  (two)
);

ysyx_040450_gen_prod #(WIDTH+2) u_gen_prod (
	.A    ( operand_a_r ),
	.neg  ( neg         ),
	.zero ( zero        ),
	.one  ( one         ),
	.two  ( two         ),
	.prod ( prod        )
);

always @(posedge clk) begin
	if(!resetn) mul_result <= {2*(WIDTH+2){1'b0}};
    else if(mult_valid_i) begin
		mul_result <= {2*(WIDTH+2){1'b0}};
	end else begin
		mul_result <= {mul_result[2*(WIDTH+2)-3:0], 2'b00} + prod;
	end
end

// FIXME 修改为无新输入则保持上一输出
assign result_o = mul_result[2*WIDTH-1:0];

endmodule

module ysyx_040450_booth_enc(
	input [2:0] code,
	output neg,
	output zero,
	output one,
	output two
);

assign neg  = code[2];
assign zero = (code==3'b000) || (code==3'b111);
assign two  = (code==3'b100) || (code==3'b011);
assign one  = !zero & !two;

endmodule

module ysyx_040450_gen_prod #(parameter WIDTH=16) (
	input [WIDTH-1:0] A,
	input neg,
	input zero,
	input one,
	input two,
	output [WIDTH*2-1:0] prod
);

reg [WIDTH*2-1:0] prod_pre;

always @ (*) begin
	prod_pre = {WIDTH*2{1'b0}};
	if (zero)
		prod_pre = {WIDTH*2{1'b0}};
	else if (one)
		prod_pre = { { WIDTH{A[WIDTH-1]} }, A};
	else if (two)
		prod_pre = { { WIDTH-1{A[WIDTH-1]} }, A, 1'b0};
end

assign prod = neg ? ( ~prod_pre+1'b1 ) : prod_pre;
		
endmodule
// 20220524
module ysyx_040450_divider #(parameter WIDTH=8) (
    input              div_valid_i   ,
    output             div_ready_o   ,
    input              div_signed_i  ,
    input  [WIDTH-1:0] dividend_i    ,
    input  [WIDTH-1:0] divisor_i     ,
    output [WIDTH-1:0] quotient_o    ,
    output [WIDTH-1:0] remainder_o   ,
    output             div_complete_o,

    input clk,
    input resetn
);

// cnt
wire [6:0] cnt_num = WIDTH+1;
reg [6:0] counter; // TODO 寄存器宽度参数化
always @(posedge clk) begin
    if(!resetn) counter <= 7'b0;
    else if(div_valid_i) counter <= cnt_num;
    else if (|counter) begin
        counter <= counter - 1'b1;
    end
end
////////////////////////// 
// step.1. 输入调整
////////////////////////// 
// 获取除数/被除数绝对值
wire [WIDTH-1:0] abs_dividend;
wire [WIDTH-1:0] abs_divisor ;
wire signed_of_dividend;
wire signed_of_divisor ;
wire signed_of_quotient ;
wire signed_of_remainder;
assign signed_of_dividend = (div_signed_i & dividend_i[WIDTH-1]);
assign signed_of_divisor  = (div_signed_i & divisor_i[WIDTH-1]);
assign abs_dividend = signed_of_dividend ? ~dividend_i+1 : dividend_i;
assign abs_divisor  = signed_of_divisor  ? ~divisor_i+1 : divisor_i;
// 输出的符号
assign signed_of_quotient  = signed_of_dividend ^ signed_of_divisor; // 商的符号
assign signed_of_remainder = signed_of_dividend; // 余数的符号与被除数一致

////////////////////////// 
// step.2. 迭代试商
////////////////////////// 
// reg [WIDTH*2-1:0] dividend_r ;
reg [WIDTH-1:0] divisor_r  ;
reg [WIDTH-1:0] quotient_r ;
reg [WIDTH*2-1:0] remainder_r;
wire [WIDTH*2-1:0] next_remainder;

always @(posedge clk) begin
    if(!resetn) divisor_r <= {WIDTH{1'b0}};
    else if(div_valid_i) begin
        // dividend_r <= abs_dividend;
        divisor_r  <= abs_divisor ;
    end
end

// compare_res[WIDTH] = 0 结果为正 部分商为1
// compare_res[WIDTH] = 1 结果为负 部分商为0
wire [WIDTH:0] compare_op_a = remainder_r[WIDTH*2-1:WIDTH-1];
wire [WIDTH:0] compare_op_b = {1'b0, divisor_r};
wire [WIDTH:0] compare_res = compare_op_a - compare_op_b;
wire compare_signed = compare_res[WIDTH];

assign next_remainder = compare_signed ? {remainder_r[WIDTH*2-2:0], 1'b0} :
                                        {compare_res[WIDTH-1:0], remainder_r[WIDTH-2:0], 1'b0};
always @(posedge clk) begin
	if(!resetn) remainder_r <= {WIDTH*2{1'b0}};
    else if(div_valid_i) begin
		remainder_r <= {{WIDTH{1'b0}}, abs_dividend};
	end else begin
		remainder_r <= next_remainder;
	end
end

always @(posedge clk) begin
	if(!resetn) quotient_r <= {WIDTH{1'b0}};
    else if(div_valid_i) begin
		quotient_r <= {WIDTH{1'b0}};
	end else begin
		quotient_r[counter-2] <= ~compare_signed;
	end
end

////////////////////////// 
// step.3. 输出值调整
////////////////////////// 
assign div_complete_o = (counter==1);
assign div_ready_o = ~|counter;
assign quotient_o  = signed_of_quotient  ? ~quotient_r+1 : quotient_r;
assign remainder_o = signed_of_remainder ? ~remainder_r[WIDTH*2-1:WIDTH]+1 :
                                            remainder_r[WIDTH*2-1:WIDTH];

endmodule

module ysyx_040450_exe_mdu(
    input       [15:0]  mdu_op_i    ,
    input               is_word_op_i,
    input       [63:0]  in_a_i  ,
    input       [63:0]  in_b_i  ,
    output      [63:0]  result_o    ,
// FIXME 未处理mem stage存在阻塞的情况
//      ms阻塞时，由于mdu_i_valid_i仍有效，可能会导致重新执行运算
    // input               mdu_flush_i  ,
    input               mdu_i_valid_i, // 单条指令应只有一个周期有效
    // output              mdu_i_ready_o,
    output              mdu_o_valid_o, // 输入下一组计算前保持输出
    // input               mdu_o_ready_i,

    input clk,
    input rst_n
);

wire op_mul    = mdu_op_i[`ysyx_040450_MDU_OP_MUL   ];
wire op_mulh   = mdu_op_i[`ysyx_040450_MDU_OP_MULH  ];
wire op_mulhsu = mdu_op_i[`ysyx_040450_MDU_OP_MULHSU];
wire op_mulhu  = mdu_op_i[`ysyx_040450_MDU_OP_MULHU ];
wire op_div    = mdu_op_i[`ysyx_040450_MDU_OP_DIV   ];
wire op_divu   = mdu_op_i[`ysyx_040450_MDU_OP_DIVU  ];
wire op_rem    = mdu_op_i[`ysyx_040450_MDU_OP_REM   ];
wire op_remu   = mdu_op_i[`ysyx_040450_MDU_OP_REMU  ];

wire mul_op;
wire div_op;
wire mul_load;
wire div_load;
wire mul_i_ready;
wire div_i_ready;
wire mul_o_valid;
wire div_o_valid;

wire mul_in_a_signed;
wire mul_in_b_signed;

wire div_signed;

wire [`ysyx_040450_XLEN-1:0] result_dualword;
wire [`ysyx_040450_XLEN*2-1:0] mul_result_full; // 128bits
wire [`ysyx_040450_XLEN-1:0] mul_result;
wire [`ysyx_040450_XLEN-1:0] div_result_quotient;
wire [`ysyx_040450_XLEN-1:0] div_result_remainder;
wire [`ysyx_040450_XLEN-1:0] div_result;

assign mul_op = op_mul | op_mulh | op_mulhsu | op_mulhu;
assign div_op = op_div | op_divu | op_rem | op_remu;
assign mul_load = mdu_i_valid_i && mul_op && mul_i_ready;
assign div_load = mdu_i_valid_i && div_op && div_i_ready;
// ---------------------
// Input Pre-process
// ---------------------
wire [63:0] a;
wire [63:0] b;
wire needSext;
assign needSext = op_mul | op_div | op_rem;
assign a =  (is_word_op_i &  needSext) ? {{32{in_a_i[31]}}, in_a_i[31:0]} :
            (is_word_op_i & !needSext) ? {{32{1'b0}}, in_a_i[31:0]} :
                                          in_a_i;
assign b =  (is_word_op_i &  needSext) ? {{32{in_b_i[31]}}, in_b_i[31:0]} :
            (is_word_op_i & !needSext) ? {{32{1'b0}}, in_b_i[31:0]} :
                                          in_b_i;
// sign flags
assign mul_in_a_signed = op_mulh | op_mulhsu;
assign mul_in_b_signed = op_mulh;
assign div_signed = op_div | op_rem;
// ---------------------
// Output Arbitration
// ---------------------
// assign mdu_i_ready_o = mul_i_ready & div_i_ready;
assign mdu_o_valid_o = mul_op ? mul_o_valid : div_o_valid;
assign result_dualword = mul_op ? mul_result : div_result;
assign result_o = (is_word_op_i) ? {{32{result_dualword[31]}}, result_dualword[31:0]} : result_dualword;
// ---------------------
// Multiplication
// ---------------------
assign mul_result = op_mul ? mul_result_full[`ysyx_040450_XLEN-1:0] :
                    mul_result_full[`ysyx_040450_XLEN*2-1:`ysyx_040450_XLEN];
ysyx_040450_multiplier #(
    .WIDTH       ( `ysyx_040450_XLEN )
) i_multiplier (
    .mult_valid_i(mul_load),
    .mult_valid_o(mul_o_valid),
    .mult_ready_o(mul_i_ready),
    .signed_a_i  (mul_in_a_signed),
    .signed_b_i  (mul_in_b_signed),
    .is_half_op_i(is_word_op_i),
    .operand_a_i (a),
    .operand_b_i (b),
    .result_o    (mul_result_full),
    
    .clk(clk),
    .resetn(rst_n)
);

// ---------------------
// Divider
// ---------------------
assign div_result = (op_div | op_divu) ? div_result_quotient :
                                        div_result_remainder;
ysyx_040450_divider #(
    .WIDTH       ( `ysyx_040450_XLEN )
) i_div (
    .div_valid_i   (div_load),
    .div_ready_o   (div_i_ready),
    .div_signed_i  (div_signed),
    .dividend_i    (a),
    .divisor_i     (b),
    .quotient_o    (div_result_quotient),
    .remainder_o   (div_result_remainder),
    .div_complete_o(div_o_valid),
    
    .clk(clk),
    .resetn(rst_n)
);

endmodule

module ysyx_040450_alu (
    input       [15:0]  alu_op   ,
    input               is_word_op,
    input       [63:0]  in_a     ,
    input       [63:0]  in_b     ,
    output      [63:0]  result
);

wire op_add  = alu_op[`ysyx_040450_ALU_OP_ADD ];
wire op_sub  = alu_op[`ysyx_040450_ALU_OP_SUB ];
wire op_sll  = alu_op[`ysyx_040450_ALU_OP_SLL ];
wire op_slt  = alu_op[`ysyx_040450_ALU_OP_SLT ];
wire op_sltu = alu_op[`ysyx_040450_ALU_OP_SLTU];
wire op_xor  = alu_op[`ysyx_040450_ALU_OP_XOR ];
wire op_srl  = alu_op[`ysyx_040450_ALU_OP_SRL ];
wire op_sra  = alu_op[`ysyx_040450_ALU_OP_SRA ];
wire op_or   = alu_op[`ysyx_040450_ALU_OP_OR  ];
wire op_and  = alu_op[`ysyx_040450_ALU_OP_AND ];
wire op_imm  = alu_op[`ysyx_040450_ALU_OP_IMM ];

wire [63:0] res_add ;
wire [63:0] res_sub ;
wire [63:0] res_sll ;
wire [63:0] res_slt ;
wire [63:0] res_sltu;
wire [63:0] res_xor ;
wire [63:0] res_srl ;
wire [63:0] res_sra ;
wire [63:0] res_or  ;
wire [63:0] res_and ;
wire [63:0] res_imm ;

wire [63:0] inter_result;

wire [63:0] a = (is_word_op) ? {{32{in_a[31]}},in_a[31:0]} : in_a;
wire [63:0] b = (is_word_op) ? {{32{in_b[31]}},in_b[31:0]} : in_b;

wire [5:0] shamt;
assign shamt[4:0] = in_b[4:0];
assign shamt[5] = (is_word_op) ? 1'b0 : in_b[5];

assign res_add  = a + b;
assign res_sub  = a - b;
assign res_sll  = a << shamt;
assign res_slt  = {63'd0,$signed(a) < $signed(b)};
assign res_sltu = {63'd0,a < b};
assign res_xor  = a ^ b;
assign res_srl  = (is_word_op ? {{32{1'b0}},a[31:0]} : a) >> shamt;
assign res_sra  = $signed(a) >>> shamt;
assign res_or   = a | b;
assign res_and  = a & b;
assign res_imm  = b;

assign inter_result = ({64{op_add }} & res_add )
                    | ({64{op_sub }} & res_sub )
                    | ({64{op_sll }} & res_sll )
                    | ({64{op_slt }} & res_slt )
                    | ({64{op_sltu}} & res_sltu)
                    | ({64{op_xor }} & res_xor )
                    | ({64{op_srl }} & res_srl )
                    | ({64{op_sra }} & res_sra )
                    | ({64{op_or  }} & res_or  )
                    | ({64{op_and }} & res_and )
                    | ({64{op_imm }} & res_imm );

assign result = is_word_op ? {{32{inter_result[31]}},inter_result[31:0]} : inter_result;

endmodule
module ysyx_040450_cache_ram(
    input [15:0] wea,
    input [6:0] addra,
    input [127:0] dina ,
    output [127:0] douta,
    `ifdef ysyx_040450_extern_cache_ram
    output[5:0]   io_sram0_addr    ,
    output        io_sram0_cen     ,
    output        io_sram0_wen     ,
    output[127:0] io_sram0_wmask   ,
    output[127:0] io_sram0_wdata   ,
    input[127:0]  io_sram0_rdata   ,
    output[5:0]   io_sram1_addr    ,
    output        io_sram1_cen     ,
    output        io_sram1_wen     ,
    output[127:0] io_sram1_wmask   ,
    output[127:0] io_sram1_wdata   ,
    input[127:0]  io_sram1_rdata   ,
    `endif
    input clka
);
reg chip_sel;
wire WEN0;
wire WEN1;
wire [127:0] rdata0,rdata1;
wire WEN;
wire [127:0] BWEN;
assign WEN0 = ~(addra[6]==1'b0 && WEN==1'b0);
assign WEN1 = ~(addra[6]==1'b1 && WEN==1'b0);
assign WEN = ~|wea;
assign BWEN = ~{
    {8{wea[15]}},
    {8{wea[14]}},
    {8{wea[13]}},
    {8{wea[12]}},
    {8{wea[11]}},
    {8{wea[10]}},
    {8{wea[9]}},
    {8{wea[8]}},
    {8{wea[7]}},
    {8{wea[6]}},
    {8{wea[5]}},
    {8{wea[4]}},
    {8{wea[3]}},
    {8{wea[2]}},
    {8{wea[1]}},
    {8{wea[0]}}
  };

`ifdef ysyx_040450_extern_cache_ram
assign io_sram0_addr    = addra[5:0];
assign io_sram0_cen     = 1'b0;
assign io_sram0_wen     = WEN0;
assign io_sram0_wmask   = BWEN;
assign io_sram0_wdata   = dina;
assign rdata0 = io_sram0_rdata;
assign io_sram1_addr    = addra[5:0];
assign io_sram1_cen     = 1'b0;
assign io_sram1_wen     = WEN1;
assign io_sram1_wmask   = BWEN;
assign io_sram1_wdata   = dina;
assign rdata1 = io_sram1_rdata;
`else // 使用内置
S011HD1P_X32Y2D128_BW cache_ram0(
    .Q   (rdata0), 
    .CLK (clka), 
    .CEN (1'b0), 
    .WEN (WEN0), 
    .BWEN(BWEN), 
    .A   (addra[5:0]), 
    .D   (dina)
);
S011HD1P_X32Y2D128_BW cache_ram1(
    .Q   (rdata1), 
    .CLK (clka), 
    .CEN (1'b0), 
    .WEN (WEN1), 
    .BWEN(BWEN), 
    .A   (addra[5:0]), 
    .D   (dina)
);
`endif
// 读出有一周期延迟
always@(posedge clka) begin
    chip_sel <= addra[6];
end

assign douta = chip_sel ? rdata1 : rdata0;
endmodule
module ysyx_040450_cache_unit
(
    input         clk     ,
    input         resetn    ,
    output        trans_done,
    output        syncing,
    /*with CPU              */
    input         valid     ,
    input         op        ,
    input  [ 6:0] index     , // addr[10:4]
    input  [20:0] tag       , // addr[31:11]
    input  [ 3:0] offset    , // addr[3:0]
    input  [ 1:0] size      ,
    input  [ 7:0] wstrb     ,
    input  [63:0] wdata     ,
    output        addr_ok   ,
    output        data_ok   ,
    output [63:0] rdata     ,
    /*for sync             */
    input          sync_rvld    , // 读请求
    output         sync_rrdy    , // 读应答
    output         sync_rdata_ok, // 数据有效
    input  [  6:0] sync_rindex  , // $line index
    output [ 43:0] sync_rinfos  , // tag v d 22b
    output [255:0] sync_rdatas  , // 数据
    input          sync_wvld  , // 写请求
    output         sync_wrdy  , // 写应答
    input  [  6:0] sync_windex, // $line index
    input  [ 43:0] sync_wtagvs, // tag v 22b
    input  [255:0] sync_wdatas, // 数据
    `ifdef ysyx_040450_extern_cache_ram
    output[5:0]   io_sram0_addr    ,
    output        io_sram0_cen     ,
    output        io_sram0_wen     ,
    output[127:0] io_sram0_wmask   ,
    output[127:0] io_sram0_wdata   ,
    input[127:0]  io_sram0_rdata   ,
    output[5:0]   io_sram1_addr    ,
    output        io_sram1_cen     ,
    output        io_sram1_wen     ,
    output[127:0] io_sram1_wmask   ,
    output[127:0] io_sram1_wdata   ,
    input[127:0]  io_sram1_rdata   ,
    output[5:0]   io_sram2_addr    ,
    output        io_sram2_cen     ,
    output        io_sram2_wen     ,
    output[127:0] io_sram2_wmask   ,
    output[127:0] io_sram2_wdata   ,
    input[127:0]  io_sram2_rdata   ,
    output[5:0]   io_sram3_addr    ,
    output        io_sram3_cen     ,
    output        io_sram3_wen     ,
    output[127:0] io_sram3_wmask   ,
    output[127:0] io_sram3_wdata   ,
    input[127:0]  io_sram3_rdata   ,
    `endif
    /*with AXI              */
    output        rd_req    ,
    output [ 2:0] rd_type   ,
    output [63:0] rd_addr   ,
    input         rd_rdy    ,
    input         ret_valid ,
    input         ret_last  ,
    input  [63:0] ret_data  ,

    output        wr_req    ,
    output [ 2:0] wr_type   ,
    output [63:0] wr_addr   ,
    output [ 7:0] wr_wstrb  ,
    output [127:0]wr_data   ,
    input         wr_rdy    ,
    input         wr_done   
);

parameter LINE_NUM = 128;
parameter LINE_ADDR_WIDTH = 7;

// load clash with W_WRITE hit
wire        collided   ;
//cache controller
//way0_tagv_ram -> regfile
reg [21:0] way0_tagv [LINE_NUM-1:0];
wire        way0_tagv_wea;
wire [LINE_ADDR_WIDTH-1:0] way0_tagv_addr;
wire [21:0] way0_tagv_in;
wire [21:0] way0_tagv_out;
//way1_tagv_ram -> regfile
reg [21:0] way1_tagv [LINE_NUM-1:0];
wire        way1_tagv_wea;
wire [LINE_ADDR_WIDTH-1:0] way1_tagv_addr;
wire [21:0] way1_tagv_in;
wire [21:0] way1_tagv_out;
//way0_ram
wire [ 7:0] way0_bank0_wea;
wire [ 7:0] way0_bank1_wea;
wire [ 15:0] way0_ram_wea;
wire [ 6:0] way0_ram_addr;
wire [63:0] way0_bank0_in;
wire [63:0] way0_bank1_in;
wire [127:0] way0_ram_in;
wire [127:0] way0_ram_out;
//way1_ram
wire [ 7:0] way1_bank0_wea;
wire [ 7:0] way1_bank1_wea;
wire [ 15:0] way1_ram_wea;
wire [ 6:0] way1_ram_addr;
wire [63:0] way1_bank0_in;
wire [63:0] way1_bank1_in;
wire [127:0] way1_ram_in;
wire [127:0] way1_ram_out;
//way0_dirty regfile
reg [LINE_NUM-1:0] way0_dirty;
wire        way0_dirty_wea;
wire [LINE_ADDR_WIDTH-1:0] way0_dirty_addr;
wire        way0_dirty_in;
wire        way0_dirty_out;
//way1_dirty regfile
reg [LINE_NUM-1:0] way1_dirty;
wire        way1_dirty_wea;
wire [LINE_ADDR_WIDTH-1:0] way1_dirty_addr;
wire        way1_dirty_in;
wire        way1_dirty_out;
//request buffer
reg         reg_op     ;
reg  [ 6:0] reg_index  ;
reg  [20:0] reg_tag    ;
reg  [ 3:0] reg_offset ;
reg  [ 1:0] reg_size   ;
reg  [ 7:0] reg_wstrb  ;
reg  [63:0] reg_wdata  ;
// sync
reg  [  6:0] reg_sync_index;
reg  [ 43:0] reg_sync_wtagvs;
wire [ 21:0] reg_sync_wtagv_way0=reg_sync_wtagvs[21:0];
wire [ 21:0] reg_sync_wtagv_way1=reg_sync_wtagvs[43:22];
wire         reg_sync_w_way0_v=reg_sync_wtagvs[0];
wire         reg_sync_w_way1_v=reg_sync_wtagvs[22];
reg  [255:0] reg_sync_wdatas;
wire [127:0] reg_sync_wdata_way0=reg_sync_wdatas[127:0];
wire [127:0] reg_sync_wdata_way1=reg_sync_wdatas[255:128];
reg          wr2mem_way;
wire [ 20:0] wr2mem_tag;
wire         wr2mem_dirty;
wire [127:0] wr2mem_data;
wire         need_wr2mem;
wire         ready_wr2mem; // wr2mem_way 指向 dirty路
//tag compare
wire        way0_v     ;
wire [20:0] way0_tag   ;
wire        way1_v     ;
wire [20:0] way1_tag   ;  
wire        way0_hit   ;
wire        way1_hit   ;
wire        cache_hit  ;
//data select
wire [ 3:0] pa         ;
wire [127:0] way0_data ;
wire [127:0] way1_data ;
wire [63:0] way0_load_dword;
wire [63:0] way1_load_dword;
wire [63:0] load_res   ;
wire [127:0] replace_data ;
//miss buffer
reg         replace_way;
reg  [ 2:0] ret_cnt    ; //max=2
//LFSR
reg  [ 2:0] r_lfsr     ;
wire        r_xnor     ;
//W_WRITE buffer
reg  [ 6:0] reg_s_index ;
reg         reg_s_way   ;
reg  [ 7:0] reg_s_wstrb ;
reg  [63:0] reg_s_wdata ;
reg  [ 3:0] reg_s_offset;
//interface with AXI
reg         wr_req_d;


/*MAIN FSM                  */
parameter IDLE        = 8'b00000001;
parameter LOOKUP      = 8'b00000010;
parameter MISS        = 8'b00000100;
parameter REPLACE     = 8'b00001000;
parameter REFILL      = 8'b00010000;
parameter SYNC_R      = 8'b00100000;
parameter SYNC_WR2MEM = 8'b01000000;
parameter SYNC_W      = 8'b10000000;
reg [7:0] m_state_c;    //main FSM current state
reg [7:0] m_state_n;    //main FSM next state

always @(posedge clk)begin 
    if(!resetn) m_state_c <= IDLE;
    else m_state_c <= m_state_n;
end 

always @(*)begin 
    case(m_state_c)
        IDLE:begin 
            if(collided==1'b1)begin 
                m_state_n = IDLE;
            end 
            else if (sync_rvld) begin
                m_state_n = SYNC_R;
            end
            else if (sync_wvld) begin
                m_state_n = SYNC_W;
            end
            else if(valid==1'b1)begin 
                m_state_n = LOOKUP;
            end
            else begin  //else if(valid==1'b0)
                m_state_n = IDLE;
            end 
        end
        LOOKUP:begin 
            if(cache_hit==1'b1 && (valid==1'b0 || collided==1'b1))begin 
                m_state_n = IDLE;
            end 
            else if(cache_hit==1'b1 && valid==1'b1)begin 
                m_state_n = LOOKUP;
            end
            else if(cache_hit==1'b0)begin
                m_state_n = MISS;
            end  //no else
        end
        MISS:begin 
            if(wr_rdy==1'b0)begin 
                m_state_n = MISS;
            end 
            else if(wr_rdy==1'b1)begin
                m_state_n = REPLACE;
            end //no else
        end 
        REPLACE:begin 
            if(rd_rdy==1'b0)begin
                m_state_n = REPLACE;
            end 
            else if(rd_rdy==1'b1)begin 
                m_state_n = REFILL;
            end //no else
        end
        REFILL:begin 
            if(ret_valid==1'b1 && ret_last==1'b1)begin 
                m_state_n = IDLE;
            end 
            else begin
                m_state_n = REFILL;
            end 
        end 
        SYNC_R:begin 
            if(need_wr2mem==1'b1)begin
                m_state_n = (wr_rdy&ready_wr2mem) ? SYNC_WR2MEM : SYNC_R;
            end
            else begin 
                m_state_n = IDLE;
            end 
        end 
        SYNC_WR2MEM:begin 
            m_state_n = SYNC_R;
        end 
        SYNC_W:begin 
            m_state_n = IDLE;
        end 
        default: m_state_n = IDLE;
    endcase
end 

/*W_WRITE Buffer FSM          */
parameter W_IDLE = 2'b01;
parameter W_WRITE = 2'b10;
reg [1:0] w_state_c;    //W_WRITE FSM current state
reg [1:0] w_state_n;    //W_WRITE FSM next state

always @(posedge clk)begin 
    if(!resetn) w_state_c <= W_IDLE;
    else w_state_c <= w_state_n;
end 

always @(*)begin 
    case(w_state_c)
        W_IDLE:begin 
            if(m_state_c==LOOKUP && reg_op==1'b1 && cache_hit==1'b1)begin 
                w_state_n = W_WRITE;
            end 
            else begin 
                w_state_n = W_IDLE;
            end 
        end
        W_WRITE:begin 
            if(m_state_c==LOOKUP && reg_op==1'b1 && cache_hit==1'b1)begin 
                w_state_n = W_WRITE;
            end 
            else begin 
                w_state_n = W_IDLE;
            end 
        end 
        default: w_state_n = W_IDLE;
    endcase
end 

/*load clash with hit W_WRITE*/
// FIXME 条件可能太宽了
assign collided = (m_state_c==LOOKUP && reg_op==1'b1 /*&& cache_hit==1'b1*/ && valid==1'b1 && op==1'b0 /*&& offset[3:2]==reg_offset[3:2]*/) |
                  (w_state_c==W_WRITE && valid==1'b1 && op==1'b0 /*&& offset[3:2]==reg_offset[3:2]*/);

/*cache controller              */
//way0_tagv_ram
assign way0_tagv_wea = (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b0) ? 1'b1 : 
                       (m_state_c==SYNC_W) ? 1'b1 : 1'b0;
// 以上代码存在组合逻辑环，考虑way0_tagv_addr仅与状态相关，删除了多余的条件
assign way0_tagv_addr = ((m_state_c==IDLE && sync_rvld==1'b1) /*|| (m_state_c==SYNC_R && sync_rvld==1'b1 && collided==1'b0)*/) ? sync_rindex : 
                        ((m_state_c==IDLE && valid==1'b1) || (m_state_c==LOOKUP)) ? index : 
                        (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM || m_state_c==SYNC_W) ? reg_sync_index : 
                        (m_state_c==MISS) ? reg_index : 
                        (m_state_c==REFILL) ? reg_index : 7'b0;
assign way0_tagv_in = (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b0) ? {reg_tag,1'b1} : 
                      (m_state_c==SYNC_W) ? reg_sync_wtagv_way0 : 22'b0;
//way1_tagv_ram
assign way1_tagv_wea = (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b1) ? 1'b1 : 
                       (m_state_c==SYNC_W) ? 1'b1 : 1'b0;
assign way1_tagv_addr = ((m_state_c==IDLE && sync_rvld==1'b1) /*|| (m_state_c==SYNC_R && sync_rvld==1'b1 && collided==1'b0)*/) ? sync_rindex : 
                        ((m_state_c==IDLE && valid==1'b1) || (m_state_c==LOOKUP)) ? index : 
                        (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM || m_state_c==SYNC_W) ? reg_sync_index : 
                        (m_state_c==MISS) ? reg_index : 
                        (m_state_c==REFILL) ? reg_index : 7'b0;
assign way1_tagv_in = (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b1) ? {reg_tag,1'b1} : 
                      (m_state_c==SYNC_W) ? reg_sync_wtagv_way1 : 22'b0;

wire [63:0] bits_wstrb = {{8{reg_wstrb[7]}},
                          {8{reg_wstrb[6]}},
                          {8{reg_wstrb[5]}},
                          {8{reg_wstrb[4]}},
                          {8{reg_wstrb[3]}},
                          {8{reg_wstrb[2]}},
                          {8{reg_wstrb[1]}},
                          {8{reg_wstrb[0]}}
                         };
wire [63:0] bits_wstrb_n = ~bits_wstrb;
wire [63:0] merge_wr_rd_data = bits_wstrb & reg_wdata | bits_wstrb_n & ret_data;
//way0_ram
assign way0_bank0_wea = (w_state_c==W_WRITE && reg_s_way==1'b0 && reg_s_offset[3]==1'd0) ? reg_s_wstrb : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b0 && reg_op==1'b1 && reg_offset[3]==1'd0) ? 8'b11111111/*reg_wstrb*/ : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b0) ? 8'b11111111 : 
                        (m_state_c==SYNC_W && reg_sync_w_way0_v) ? 8'b11111111 : 8'b0;
assign way0_bank1_wea = (w_state_c==W_WRITE && reg_s_way==1'b0 && reg_s_offset[3]==1'd1) ? reg_s_wstrb : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b0 && reg_op==1'b1 && reg_offset[3]==1'd1) ? 8'b11111111/*reg_wstrb*/ : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b0) ? 8'b11111111 : 
                        (m_state_c==SYNC_W && reg_sync_w_way0_v) ? 8'b11111111 : 8'b0;
assign way0_ram_wea = {way0_bank1_wea,way0_bank0_wea};//{way0_bank0_wea,way0_bank1_wea};
assign way0_ram_addr = (w_state_c==W_WRITE && reg_s_way==1'b0 /*&& reg_s_offset[3:2]==2'd0*/) ? reg_s_index : 
                        ((m_state_c==IDLE && sync_rvld==1'b1) /*|| (m_state_c==SYNC_R && sync_rvld==1'b1 && collided==1'b0)*/) ? sync_rindex : 
                        ((m_state_c==IDLE && valid==1'b1) || (m_state_c==LOOKUP && cache_hit==1'b1 && valid==1'b1 && collided==1'b0)) ? index : 
                        (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM || m_state_c==SYNC_W) ? reg_sync_index : 
                        (m_state_c==MISS && wr_rdy==1'b1) ? reg_index : 
                        (m_state_c==REFILL && ret_valid==1'b1 /*&& ret_cnt==3'd0*/ && replace_way==1'b0) ? reg_index : 7'b0;
assign way0_bank0_in = (w_state_c==W_WRITE && reg_s_way==1'b0 && reg_s_offset[3]==1'd0) ? reg_s_wdata : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b0 && reg_op==1'b1 && reg_offset[3]==1'd0) ? merge_wr_rd_data/*reg_wdata*/ : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b0) ? ret_data : 
                       (m_state_c==SYNC_W && reg_sync_w_way0_v) ? reg_sync_wdata_way0[63:0] : 64'b0;
assign way0_bank1_in = (w_state_c==W_WRITE && reg_s_way==1'b0 && reg_s_offset[3]==1'd1) ? reg_s_wdata : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b0 && reg_op==1'b1 && reg_offset[3]==1'd1) ? merge_wr_rd_data/*reg_wdata*/ : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b0) ? ret_data : 
                       (m_state_c==SYNC_W && reg_sync_w_way0_v) ? reg_sync_wdata_way0[127:64] : 64'b0;
assign way0_ram_in = {way0_bank1_in,way0_bank0_in};//{way0_bank0_in,way0_bank1_in};
//way1_ram
assign way1_bank0_wea = (w_state_c==W_WRITE && reg_s_way==1'b1 && reg_s_offset[3]==1'd0) ? reg_s_wstrb : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b1 && reg_op==1'b1 && reg_offset[3]==1'd0) ? 8'b11111111/*reg_wstrb*/ : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b1) ? 8'b11111111 : 
                        (m_state_c==SYNC_W && reg_sync_w_way1_v) ? 8'b11111111 : 8'b0;
assign way1_bank1_wea = (w_state_c==W_WRITE && reg_s_way==1'b1 && reg_s_offset[3]==1'd1) ? reg_s_wstrb : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b1 && reg_op==1'b1 && reg_offset[3]==1'd1) ? 8'b11111111/*reg_wstrb*/ : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b1) ? 8'b11111111 : 
                        (m_state_c==SYNC_W && reg_sync_w_way1_v) ? 8'b11111111 : 8'b0;
assign way1_ram_wea = {way1_bank1_wea,way1_bank0_wea};//{way1_bank0_wea,way1_bank1_wea};
assign way1_ram_addr = (w_state_c==W_WRITE && reg_s_way==1'b1 /*&& reg_s_offset[3:2]==2'd0*/) ? reg_s_index : 
                        ((m_state_c==IDLE && sync_rvld==1'b1) /*|| (m_state_c==SYNC_R && sync_rvld==1'b1 && collided==1'b0)*/) ? sync_rindex : 
                        ((m_state_c==IDLE && valid==1'b1) || (m_state_c==LOOKUP && cache_hit==1'b1 && valid==1'b1 && collided==1'b0)) ? index : 
                        (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM || m_state_c==SYNC_W) ? reg_sync_index : 
                        (m_state_c==MISS && wr_rdy==1'b1) ? reg_index : 
                        (m_state_c==REFILL && ret_valid==1'b1 /*&& ret_cnt==3'd0*/ && replace_way==1'b1) ? reg_index : 7'b0;
assign way1_bank0_in = (w_state_c==W_WRITE && reg_s_way==1'b1 && reg_s_offset[3]==1'd0) ? reg_s_wdata : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b1 && reg_op==1'b1 && reg_offset[3]==1'd0) ? merge_wr_rd_data/*reg_wdata*/ : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd0 && replace_way==1'b1) ? ret_data : 
                       (m_state_c==SYNC_W && reg_sync_w_way1_v) ? reg_sync_wdata_way1[63:0] : 64'b0;
assign way1_bank1_in = (w_state_c==W_WRITE && reg_s_way==1'b1 && reg_s_offset[3]==1'd1) ? reg_s_wdata : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b1 && reg_op==1'b1 && reg_offset[3]==1'd1) ? merge_wr_rd_data/*reg_wdata*/ : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt==3'd1 && replace_way==1'b1) ? ret_data : 
                        (m_state_c==SYNC_W && reg_sync_w_way1_v) ? reg_sync_wdata_way1[127:64] : 64'b0;
assign way1_ram_in = {way1_bank1_in,way1_bank0_in};//{way1_bank0_in,way1_bank1_in};
//way0_dirty regfile
assign way0_dirty_wea = (w_state_c==W_WRITE && reg_s_way==1'b0) ? 1'b1 : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b0) ? 1'b1 :
                        (m_state_c==SYNC_WR2MEM && wr2mem_way==1'b0) ? 1'b1 : 
                        (m_state_c==SYNC_W) ? 1'b1 : 1'b0;
assign way0_dirty_addr = (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM || m_state_c==SYNC_W) ? reg_sync_index : 
                         (m_state_c==REPLACE) ? reg_index : //next clk of (m_state_c==MISS && wr_rdy==1'b1)
                         (w_state_c==W_WRITE && reg_s_way==1'b0) ? reg_s_index : 
                         (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b0) ? reg_index : 7'b0;
assign way0_dirty_in = (w_state_c==W_WRITE && reg_s_way==1'b0) ? 1'b1 : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b0 && reg_op==1'b1) ? 1'b1 : 1'b0;
//way1_dirty regfile
assign way1_dirty_wea = (w_state_c==W_WRITE && reg_s_way==1'b1) ? 1'b1 : 
                        (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b1) ? 1'b1 :
                        (m_state_c==SYNC_WR2MEM && wr2mem_way==1'b1) ? 1'b1 : 
                        (m_state_c==SYNC_W) ? 1'b1 : 1'b0;
assign way1_dirty_addr = (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM || m_state_c==SYNC_W) ? reg_sync_index : 
                         (m_state_c==REPLACE) ? reg_index : //next clk of (m_state_c==MISS && wr_rdy==1'b1)
                         (w_state_c==W_WRITE && reg_s_way==1'b1) ? reg_s_index : 
                         (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b1) ? reg_index : 7'b0;
assign way1_dirty_in = (w_state_c==W_WRITE && reg_s_way==1'b1) ? 1'b1 : 
                       (m_state_c==REFILL && ret_valid==1'b1 && ret_last==1'b1 && replace_way==1'b1 && reg_op==1'b1) ? 1'b1 : 1'b0;

/*way0_tagv regfile        */
//WRITE
integer i;
always @(posedge clk)begin 
    if(!resetn)begin 
        for(i=0; i<128/4; i=i+1) begin
            way0_tagv[i*4  ] <= 22'b0;
            way0_tagv[i*4+1] <= 22'b0;
            way0_tagv[i*4+2] <= 22'b0;
            way0_tagv[i*4+3] <= 22'b0;
        end
    end 
    else if(way0_tagv_wea)begin 
        way0_tagv[way0_tagv_addr] <= way0_tagv_in;
    end 
end 
//READ
reg [21:0] way0_tagv_out_r;
always @(posedge clk)begin 
    if(!resetn)begin 
        way0_tagv_out_r <= 22'b0;
    end 
    else begin 
        way0_tagv_out_r <= way0_tagv[way0_tagv_addr];
    end 
end
assign way0_tagv_out = way0_tagv_out_r;
/*way1_tagv regfile        */
//WRITE
integer j;
always @(posedge clk)begin 
    if(!resetn)begin 
        for (j=0; j<128/4; j=j+1) begin
            way1_tagv[j*4  ] <= 22'b0;
            way1_tagv[j*4+1] <= 22'b0;
            way1_tagv[j*4+2] <= 22'b0;
            way1_tagv[j*4+3] <= 22'b0;
        end
    end 
    else if(way1_tagv_wea)begin 
        way1_tagv[way1_tagv_addr] <= way1_tagv_in;
    end 
end 
//READ
reg [21:0] way1_tagv_out_r;
always @(posedge clk)begin 
    if(!resetn)begin 
        way1_tagv_out_r <= 22'b0;
    end 
    else begin 
        way1_tagv_out_r <= way1_tagv[way1_tagv_addr];
    end 
end 
assign way1_tagv_out = way1_tagv_out_r;
// assign way1_tagv_out = way1_tagv[way1_tagv_addr];
// 
`ifdef ysyx_040450_extern_cache_ram
/*way0_ram             */
ysyx_040450_cache_ram way0_ram(
    .wea  (way0_ram_wea ),
    .addra(way0_ram_addr),
    .dina (way0_ram_in  ),
    .douta(way0_ram_out ),
    .io_sram0_addr (io_sram0_addr ),
    .io_sram0_cen  (io_sram0_cen  ),
    .io_sram0_wen  (io_sram0_wen  ),
    .io_sram0_wmask(io_sram0_wmask),
    .io_sram0_wdata(io_sram0_wdata),
    .io_sram0_rdata(io_sram0_rdata),
    .io_sram1_addr (io_sram1_addr ),
    .io_sram1_cen  (io_sram1_cen  ),
    .io_sram1_wen  (io_sram1_wen  ),
    .io_sram1_wmask(io_sram1_wmask),
    .io_sram1_wdata(io_sram1_wdata),
    .io_sram1_rdata(io_sram1_rdata),
    .clka (clk          )
);
/*way1_ram             */
ysyx_040450_cache_ram way1_ram(
    .wea  (way1_ram_wea ),
    .addra(way1_ram_addr),
    .dina (way1_ram_in  ),
    .douta(way1_ram_out ),
    .io_sram0_addr (io_sram2_addr ),
    .io_sram0_cen  (io_sram2_cen  ),
    .io_sram0_wen  (io_sram2_wen  ),
    .io_sram0_wmask(io_sram2_wmask),
    .io_sram0_wdata(io_sram2_wdata),
    .io_sram0_rdata(io_sram2_rdata),
    .io_sram1_addr (io_sram3_addr ),
    .io_sram1_cen  (io_sram3_cen  ),
    .io_sram1_wen  (io_sram3_wen  ),
    .io_sram1_wmask(io_sram3_wmask),
    .io_sram1_wdata(io_sram3_wdata),
    .io_sram1_rdata(io_sram3_rdata),
    .clka (clk          )
);
`else // 使用内置
/*way0_ram             */
ysyx_040450_cache_ram way0_ram(
    .clka (clk          ),
    .wea  (way0_ram_wea ),
    .addra(way0_ram_addr),
    .dina (way0_ram_in  ),
    .douta(way0_ram_out )
);
/*way1_ram             */
ysyx_040450_cache_ram way1_ram(
    .clka (clk          ),
    .wea  (way1_ram_wea ),
    .addra(way1_ram_addr),
    .dina (way1_ram_in  ),
    .douta(way1_ram_out )
);
`endif
/*way0_dirty regfile        */
//WRITE
always @(posedge clk)begin 
    if(!resetn)begin 
        way0_dirty <= 128'b0; 
    end 
    else if(way0_dirty_wea)begin 
        way0_dirty[way0_dirty_addr+:1] <= way0_dirty_in;
    end 
end 
//READ
assign way0_dirty_out = way0_dirty[way0_dirty_addr+:1];
/*way1_ditry regfile        */
//WRITE
always @(posedge clk)begin 
    if(!resetn)begin 
        way1_dirty <= 128'b0; 
    end 
    else if(way1_dirty_wea)begin 
        way1_dirty[way1_dirty_addr+:1] <= way1_dirty_in;
    end 
end 
//READ
assign way1_dirty_out = way1_dirty[way1_dirty_addr+:1];


/*data path                     */
/*Request Buffer            */
always @(posedge clk)begin                
    if((m_state_c==IDLE && valid==1'b1) || (m_state_c==LOOKUP && cache_hit==1'b1 && valid==1'b1 && collided==1'b0))begin 
        reg_op <= op;
        reg_index <= index;
        reg_tag <= tag;
        reg_offset <= offset;
        reg_size <= size;
        reg_wstrb <= wstrb;
        reg_wdata <= wdata;
    end 
    else begin
        reg_op <= reg_op;
        reg_index <= reg_index;
        reg_tag <= reg_tag;
        reg_offset <= reg_offset;
        reg_size <= reg_size;
        reg_wstrb <= reg_wstrb;
        reg_wdata <= reg_wdata;
    end 
end 
/*Sync                      */
// sync request buffer
always @(posedge clk)begin
    if((m_state_c==IDLE && sync_rvld==1'b1) /*|| (m_state_c==SYNC_R && sync_rvld==1'b1 && collided==1'b0)*/)begin
        reg_sync_index <= sync_rindex;
    end
    else if(m_state_c==IDLE && sync_wvld==1'b1)begin
        reg_sync_index <= sync_windex;
    end
    else begin
        reg_sync_index <= reg_sync_index;
    end
end
always @(posedge clk)begin
    if((m_state_c==IDLE && sync_wvld==1'b1 && sync_rvld==1'b0))begin
        reg_sync_wtagvs <= sync_wtagvs;
        reg_sync_wdatas <= sync_wdatas;
    end
    else begin
        reg_sync_wtagvs <= reg_sync_wtagvs;
        reg_sync_wdatas <= reg_sync_wdatas;
    end
end
// 写出路选择
always @(posedge clk)begin
    if((m_state_c==IDLE && sync_rvld==1'b1) /*|| (m_state_c==SYNC_R && sync_rvld==1'b1 && collided==1'b0)*/)begin
        if(way0_dirty_out) // both dirty or way0 dirty
            wr2mem_way <= 1'b0;
        else if(way1_dirty_out) // way1 dirty
            wr2mem_way <= 1'b1;
        else
            wr2mem_way <= wr2mem_way;
    end
    else if(m_state_c==SYNC_R&&(wr2mem_dirty==1'b0))begin
        wr2mem_way <= ~wr2mem_way;//wr2mem_way + 1'b1;
    end
    else
        wr2mem_way <= wr2mem_way;
end
assign wr2mem_tag   = wr2mem_way ? way1_tag : way0_tag;
assign wr2mem_dirty = wr2mem_way ? way1_dirty_out : way0_dirty_out;
assign wr2mem_data  = wr2mem_way ? way1_ram_out : way0_ram_out;
assign need_wr2mem  = (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM) && (way1_dirty_out || way0_dirty_out);
assign ready_wr2mem = (m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM) && (wr2mem_way ? way1_dirty_out : way0_dirty_out);
/*Tag Compare               */  //unconsider uncache
assign way0_v = way0_tagv_out[0];
assign way0_tag = way0_tagv_out[21:1];
assign way1_v = way1_tagv_out[0];
assign way1_tag = way1_tagv_out[21:1];
assign way0_hit = way0_v && (way0_tag == reg_tag);
assign way1_hit = way1_v && (way1_tag == reg_tag);
assign cache_hit = way0_hit || way1_hit;
/*Data Select               */
assign pa = reg_offset;
assign way0_data = way0_ram_out;
assign way1_data = way1_ram_out;
assign way0_load_dword = way0_data[pa[3]*64 +: 64];
assign way1_load_dword = way1_data[pa[3]*64 +: 64];
wire [63:0] load_data;
assign load_data = {{64{way0_hit}} & way0_load_dword} | 
                   {{64{way1_hit}} & way1_load_dword} | 
                   {{64{ret_valid}}& ret_data      } ;

wire [7:0]  load_byte;
wire [15:0] load_halfword;
wire [31:0] load_word;
ysyx_040450_MuxKey #(8, 3, 8) i_load_byte_sel (load_byte, pa[2:0], {
    3'b000, load_data[7:0],
    3'b001, load_data[15:8],
    3'b010, load_data[23:16],
    3'b011, load_data[31:24],
    3'b100, load_data[39:32],
    3'b101, load_data[47:40],
    3'b110, load_data[55:48],
    3'b111, load_data[63:56]
});
ysyx_040450_MuxKey #(4, 2, 16) i_load_halfword_sel (load_halfword, pa[2:1], {
    2'b00, load_data[15:0],
    2'b01, load_data[31:16],
    2'b10, load_data[47:32],
    2'b11, load_data[63:48]
});
ysyx_040450_MuxKey #(2, 1, 32) i_load_word_sel (load_word, pa[2], {
    1'b0, load_data[31:0],
    1'b1, load_data[63:32]
});
ysyx_040450_MuxKey #(4, 2, 64) i_load_data_sel (load_res, reg_size, {
    2'b00, {{56{1'b0}}, load_byte},
    2'b01, {{48{1'b0}}, load_halfword},
    2'b10, {{32{1'b0}}, load_word},
    2'b11, load_data
});

assign replace_data = replace_way ? way1_data : way0_data;
/*Miss Buffer               */
always @(posedge clk)begin 
    if(m_state_c==MISS && wr_rdy==1'b1)begin 
        replace_way <= r_lfsr[0]; //p(0)=4/7,p(1)=3/7
    end 
    else begin 
        replace_way <= replace_way;
    end 
end 
always @(posedge clk)begin 
    if(m_state_c==REPLACE && rd_rdy==1'b1)begin 
        ret_cnt <= 3'b0;
    end 
    else if(ret_valid==1'b1)begin
        ret_cnt <= ret_cnt + 3'b1;
    end 
    else
        ret_cnt <= ret_cnt;
end 
/*LFSR                      */
always @(posedge clk)begin 
    if(!resetn)begin 
        r_lfsr <= 3'b0;
    end 
    else begin 
        r_lfsr <= {r_lfsr[1:0],r_xnor};
    end 
end 
assign r_xnor = r_lfsr[2] ^~ r_lfsr[1];
/*WRITE Buffer              */
always @(posedge clk)begin 
    if(m_state_c==LOOKUP && reg_op==1'b1 && cache_hit==1'b1)begin 
        reg_s_index <= reg_index;
        reg_s_way <= way0_hit ? 1'b0 : 1'b1;
        reg_s_wstrb <= reg_wstrb;
        reg_s_wdata <= reg_wdata;
        reg_s_offset <= reg_offset;
    end 
    else begin 
        reg_s_index <= reg_s_index;
        reg_s_way <= reg_s_way;
        reg_s_wstrb <= reg_s_wstrb;
        reg_s_wdata <= reg_s_wdata;
        reg_s_offset <= reg_s_offset;
    end 
end 

/*interface                     */
/*interface for sync       */
assign sync_rrdy = (m_state_c==IDLE && collided==1'b0);
                // || (m_state_c==SYNC_R);
assign sync_rdata_ok = m_state_c==SYNC_R;
assign sync_rinfos   = m_state_c==SYNC_R ? {way1_tagv_out_r,way0_tagv_out_r} : 44'd0;
assign sync_rdatas   = m_state_c==SYNC_R ? {way1_ram_out,way0_ram_out} : 256'd0;

assign sync_wrdy = (m_state_c==IDLE && collided==1'b0) 
                || (m_state_c==SYNC_W);
/*interface with CPU        */
assign addr_ok = (m_state_c==IDLE && collided==1'b0) 
              || (m_state_c==LOOKUP && cache_hit==1'b1 && valid==1'b1 && collided==1'b0);
assign data_ok = (m_state_c==LOOKUP && cache_hit==1'b1) 
              || (m_state_c==LOOKUP && reg_op==1'b1) // 直接放行阻塞在MEM级的store指令 
              || (m_state_c==REFILL && ret_valid==1'b1 && ret_cnt=={2'b00,reg_offset[3]});
assign rdata = load_res;
assign trans_done = m_state_n==IDLE;
assign syncing = m_state_c==SYNC_R || m_state_c==SYNC_WR2MEM || m_state_c==SYNC_W;
/*interface with AXI        */
assign rd_req = (m_state_c==REPLACE);
assign rd_type = 3'b111;
assign rd_addr[63:4] = {32'b0,reg_tag,reg_index};
assign rd_addr[ 3:0] = 4'b0;

always @(posedge clk)begin 
    if(!resetn)begin 
        wr_req_d<= 1'b0;
    end 
    else if((m_state_c==MISS || (m_state_c==SYNC_R && ready_wr2mem)) && wr_rdy==1'b1)begin 
        wr_req_d<= 1'b1;
    end 
    else if(wr_rdy==1'b1)begin 
        wr_req_d<= 1'b0;
    end 
    else
        wr_req_d <= wr_req_d;
end 
assign wr_req = (wr_req_d==1'b1) 
            && (((m_state_c==SYNC_WR2MEM)&&((wr2mem_way==1'b0 && way0_v==1'b1 && way0_dirty_out==1'b1) || (wr2mem_way==1'b1 && way1_v==1'b1 && way1_dirty_out==1'b1)))
            || (replace_way==1'b0 && way0_v==1'b1 && way0_dirty_out==1'b1) 
            || (replace_way==1'b1 && way1_v==1'b1 && way1_dirty_out==1'b1));
assign wr_type = 3'b111; //unconsider uncache
assign wr_addr = (m_state_c==SYNC_WR2MEM) ? {32'b0,wr2mem_tag,reg_sync_index,4'b0} :
                 (replace_way==1'b0) ? {32'b0,way0_tag,reg_index,4'b0} : {32'b0,way1_tag,reg_index,4'b0};
assign wr_wstrb = 8'b11111111; //meaningless
assign wr_data = (m_state_c==SYNC_WR2MEM) ? wr2mem_data : replace_data;

// debug info 
`ifdef ysyx_040450_DBG_paser_FSM
wire [55:0] str_main_FSM_state = m_state_c==IDLE    ? "IDLE" : 
                                 m_state_c==LOOKUP  ? "LOOKUP" : 
                                 m_state_c==MISS    ? "MISS" : 
                                 m_state_c==REPLACE ? "REPLACE" : 
                                 m_state_c==REFILL  ? "REFILL" : 
                                 m_state_c==SYNC_R  ? "SYNC_R" : 
                                 m_state_c==SYNC_WR2MEM  ? "WR2MEM" : 
                                 m_state_c==SYNC_W  ? "SYNC_W" : 
                                "ERROR";
`endif

endmodule
// cache同步桥 用于处理fence.i指令
module ysyx_040450_cache_sync_bridge(
    // fence.i
    input  fencei_req,
    output fencei_ack,

    // D$
    output         sync_rvld    , // 读请求
    input          sync_rrdy    , // 读应答
    input          sync_rdata_ok, // 数据有效
    output [  6:0] sync_rindex  , // $line index
    input  [ 43:0] sync_rinfos  , // tag v d 22bx2
    input  [255:0] sync_rdatas  , // 两路数据

    // I$
    output         sync_wvld  , // 写请求
    input          sync_wrdy  , // 写应答
    output [  6:0] sync_windex, // $line index
    output [ 43:0] sync_wtagvs, // tag v 22bx2
    output [255:0] sync_wdatas, // 两路数据

    input         clk       ,
    input         resetn
);
//=================================================================================
// Parameter declaration
//=================================================================================
parameter IDLE    = 5'b00001;
parameter READ    = 5'b00010;
parameter CHECK   = 5'b00100; // 等待写入结束
parameter WRITE   = 5'b01000;
parameter DONE    = 5'b10000;

//=================================================================================
// Signal declaration
//=================================================================================
wire [ 20:0] way1_tag   = sync_rinfos[43:23];
wire         way1_valid = sync_rinfos[22];
// wire         way1_dirty = sync_rinfos[23];
wire [ 20:0] way0_tag   = sync_rinfos[21:1];
wire         way0_valid = sync_rinfos[0];
// wire         way0_dirty = sync_rinfos[0];
wire [127:0] way1_data  = sync_rdatas[255:128];
wire [127:0] way0_data  = sync_rdatas[127:0];
// read buffer
reg [ 43:0] rbuf_rinfos_r;
reg [255:0] rbuf_rdatas_r;
// counter
wire       idx_cnt_add;
wire       idx_cnt_clr;
reg [ 6:0] index_cnt;

wire need_sync;

wire hs_rd;
wire hs_wr;
wire sync_rlast;

reg [4:0] m_state_c;    //main FSM current state
reg [4:0] m_state_n;    //main FSM next state
//=================================================================================
// Body
//=================================================================================
assign hs_rd = sync_rvld & sync_rrdy;
assign hs_wr = sync_wvld & sync_wrdy;
assign sync_rlast = index_cnt==7'd127;

assign need_sync = 1'b1;//way0_valid | way1_valid;

// line counter
assign idx_cnt_add = (m_state_c==CHECK && need_sync==1'b0 && sync_rlast==1'b0)
                  || (m_state_c==WRITE && hs_wr==1'b1 && sync_rlast==1'b0);
assign idx_cnt_clr = m_state_c==IDLE && fencei_req;
always @(posedge clk)begin
    if(!resetn) index_cnt <= 7'd0;
    else if(idx_cnt_clr) index_cnt <= 7'd0;
    else if(idx_cnt_add) index_cnt <= index_cnt + 1'b1;
end

/*MAIN FSM                  */
always @(posedge clk)begin 
    if(!resetn) m_state_c <= IDLE;
    else m_state_c <= m_state_n;
end 

always @(*)begin 
    case(m_state_c)
        IDLE:begin 
            if(fencei_req==1'b1)begin 
                m_state_n = READ;
            end
            else begin  //else if(valid==1'b0)
                m_state_n = IDLE;
            end 
        end
        READ:begin 
            if(hs_rd)begin
                m_state_n = CHECK;
            end
            else begin
                m_state_n = READ;
            end //no else
        end 
        CHECK:begin 
            if(need_sync==1'b1)begin
                m_state_n = WRITE;
            end
            else if(need_sync==1'b0 && sync_rlast==1'b1)begin
                m_state_n = DONE;
            end
            else begin
                m_state_n = READ;
            end //no else
        end 
        WRITE:begin 
            if(hs_wr) begin
                if(sync_rlast)begin
                    m_state_n = DONE;
                end
                else begin
                    m_state_n = READ;
                end //no else
            end
            else
                m_state_n = WRITE;
        end 
        DONE:begin
            m_state_n = IDLE;
        end
        default: m_state_n = IDLE;
    endcase
end 

//  read buffer
always @(posedge clk) begin
    if(m_state_c==CHECK && sync_rdata_ok==1'b1) begin
        rbuf_rinfos_r <= {{21{way1_valid}}&way1_tag,way1_valid,
                          {21{way0_valid}}&way0_tag,way0_valid};
        rbuf_rdatas_r <= {{128{way1_valid}}&way1_data,
                          {128{way0_valid}}&way0_data};
    end
    else begin
        rbuf_rinfos_r <= rbuf_rinfos_r;
        rbuf_rdatas_r <= rbuf_rdatas_r;
    end
end

assign fencei_ack = (m_state_c==DONE);
// assign fencei_ack = (m_state_c==CHECK && need_sync==1'b0 && sync_rlast==1'b1)
//                  || (m_state_c==WRITE && hs_wr==1'b1 && sync_rlast==1'b1);

assign sync_rvld   = m_state_c==READ;
assign sync_rindex = index_cnt;

assign sync_wvld   = m_state_c==WRITE;
assign sync_windex = index_cnt;
assign sync_wtagvs = rbuf_rinfos_r;
assign sync_wdatas = rbuf_rdatas_r;

endmodule

module ysyx_040450_dcache(
    // with CPU
    input         cpu_sram_req    ,
    input         cpu_sram_wr     ,
    input  [1 :0] cpu_sram_size   ,
    input  [7 :0] cpu_sram_wstrb  ,
    input  [63:0] cpu_sram_addr   ,
    input  [63:0] cpu_sram_wdata  ,
    output        cpu_sram_addr_ok,
    output        cpu_sram_data_ok,
    output [63:0] cpu_sram_rdata  ,
    // sync
    input          sync_rvld    , // 读请求
    output         sync_rrdy    , // 读应答
    output         sync_rdata_ok, // 数据有效
    input  [  6:0] sync_rindex  , // $line index
    output [ 43:0] sync_rinfos  , // tag v d 22bx2
    output [255:0] sync_rdatas  , // 两路数据
    // with axi_bridge
    output        dcache_rd_req    ,
    output [ 2:0] dcache_rd_type   ,
    output [63:0] dcache_rd_addr   ,
    input         dcache_rd_rdy    ,
    input         dcache_ret_valid ,
    input         dcache_ret_last  ,
    input  [63:0] dcache_ret_data  ,
    output        dcache_wr_req    ,
    output [ 2:0] dcache_wr_type   ,
    output [63:0] dcache_wr_addr   ,
    output [ 7:0] dcache_wr_wstrb  ,
    output [127:0]dcache_wr_data   ,
    input         dcache_wr_rdy    ,
    input         dcache_wr_done   ,
    `ifdef ysyx_040450_extern_cache_ram
    output[5:0]   io_sram0_addr    ,
    output        io_sram0_cen     ,
    output        io_sram0_wen     ,
    output[127:0] io_sram0_wmask   ,
    output[127:0] io_sram0_wdata   ,
    input[127:0]  io_sram0_rdata   ,
    output[5:0]   io_sram1_addr    ,
    output        io_sram1_cen     ,
    output        io_sram1_wen     ,
    output[127:0] io_sram1_wmask   ,
    output[127:0] io_sram1_wdata   ,
    input[127:0]  io_sram1_rdata   ,
    output[5:0]   io_sram2_addr    ,
    output        io_sram2_cen     ,
    output        io_sram2_wen     ,
    output[127:0] io_sram2_wmask   ,
    output[127:0] io_sram2_wdata   ,
    input[127:0]  io_sram2_rdata   ,
    output[5:0]   io_sram3_addr    ,
    output        io_sram3_cen     ,
    output        io_sram3_wen     ,
    output[127:0] io_sram3_wmask   ,
    output[127:0] io_sram3_wdata   ,
    input[127:0]  io_sram3_rdata   ,
    `endif
    // others
    input         clk,
    input         resetn
);
//=================================================================================
// Parameter declaration
//=================================================================================


//=================================================================================
// Signal declaration
//=================================================================================
reg         cpu_sram_addr_r_valid;
reg  [63:0] cpu_sram_addr_r      ; // TODO 节省资源可改为缓存cache/uncache标志
wire [63:0] sram_addr_hold;
wire              seg_peripheral;
wire              seg_FLASH;
wire              seg_RAM;
// reg               reg_is_cache_req  ;
// reg               reg_is_uncache_req;
// wire              cpu_is_cache_req  ;
// wire              cpu_is_uncache_req;
wire              is_cache_req  ;
wire              is_uncache_req;
wire              narrow_trans;

// D$
wire        cache_trans_done; 
// D$ - cpu
wire        cache_valid  ;   
wire        cache_op     ;   
wire [ 6:0] cache_index  ;   
wire [20:0] cache_tag    ;   
wire [ 3:0] cache_offset ;   
wire [ 1:0] cache_size   ;   
wire [ 7:0] cache_wstrb  ;   
wire [63:0] cache_wdata  ;   
wire        cache_addr_ok;   
wire        cache_data_ok;   
wire [63:0] cache_rdata  ;   
// D$ - axi rd
wire        cache_rd_req   ;
wire [ 2:0] cache_rd_type  ;
wire [63:0] cache_rd_addr  ;
wire        cache_rd_rdy   ;
wire        cache_ret_valid;
wire        cache_ret_last ;
wire [63:0] cache_ret_data ;
// D$ - axi wr
wire        cache_wr_req  ;
wire [ 2:0] cache_wr_type ;
wire [63:0] cache_wr_addr ;
wire [ 7:0] cache_wr_wstrb;
wire [127:0]cache_wr_data ;
wire        cache_wr_rdy  ;
wire        cache_wr_done ;

// Uncache
wire        uncache_trans_done; 
wire        syncing;
// Uncache - cpu
wire        uncache_req    ;
wire        uncache_wr     ;
wire [1 :0] uncache_size   ;
wire [7 :0] uncache_wstrb  ;
wire [63:0] uncache_addr   ;
wire [63:0] uncache_wdata  ;
wire        uncache_addr_ok;
wire        uncache_data_ok;
wire [63:0] uncache_rdata  ;
// Uncache - axi rd
wire        uncache_rd_req   ;
wire [ 2:0] uncache_rd_type  ;
wire [63:0] uncache_rd_addr  ;
wire        uncache_rd_rdy   ;
wire        uncache_ret_valid;
wire        uncache_ret_last ;
wire [63:0] uncache_ret_data ;
// uncache - axi wr
wire        uncache_wr_req  ;
wire [ 2:0] uncache_wr_type ;
wire [63:0] uncache_wr_addr ;
wire [ 7:0] uncache_wr_wstrb;
wire [127:0]uncache_wr_data ;
wire        uncache_wr_rdy  ;
wire        uncache_wr_done ;

// ===unused====
wire sync_wrdy;

//=================================================================================
// Body
//=================================================================================
// /*MAIN FSM                  */
// parameter IDLE       = 3'b001;
// parameter CACHE_REQ   = 3'b010;
// parameter UNCACHE_REQ = 3'b100;
// reg [2:0] m_state_c;    //main FSM current state
// reg [2:0] m_state_n;    //main FSM next state

// always @(posedge clk)begin 
//     if(!resetn) m_state_c <= IDLE;
//     else m_state_c <= m_state_n;
// end 

// always @(*)begin 
//     case(m_state_c)
//         IDLE:begin 
//             if(cpu_sram_req==1'b1 && cpu_is_cache_req==1'b1)begin 
//                 m_state_n = CACHE_REQ;
//             end
//             else if(cpu_sram_req==1'b1 && cpu_is_uncache_req==1'b1)begin
//                 m_state_n = UNCACHE_REQ;
//             end
//             else begin
//                 m_state_n = IDLE;
//             end 
//         end
//         CACHE_REQ:begin 
//             if(cache_trans_done==1'b1 && cpu_sram_req==1'b1)begin // write request
//                 m_state_n = cpu_is_cache_req ? CACHE_REQ :
//                             cpu_is_uncache_req ? UNCACHE_REQ :
//                             IDLE; // 不应出现
//             end
//             else if(cache_trans_done==1'b1 && cpu_sram_req==1'b0)begin
//                 m_state_n = IDLE;
//             end
//             else begin
//                 m_state_n = CACHE_REQ;
//             end 
//         end 
//         UNCACHE_REQ:begin 
//             if(uncache_trans_done==1'b1 && cpu_sram_req==1'b1)begin // write request
//                 m_state_n = cpu_is_cache_req ? CACHE_REQ :
//                             cpu_is_uncache_req ? UNCACHE_REQ :
//                             IDLE; // 不应出现
//             end
//             else if(uncache_trans_done==1'b1 && cpu_sram_req==1'b0)begin
//                 m_state_n = IDLE;
//             end
//             else begin
//                 m_state_n = UNCACHE_REQ;
//             end 
//         end 
//         default: m_state_n = IDLE;
//     endcase
// end 

assign sram_addr_hold = cpu_sram_addr_r_valid ? cpu_sram_addr_r : cpu_sram_addr;
`ifdef ysyx_040450_ENV_ysyxSoc
// 0x1000_0000 ~ 0x2FFF_FFFF, 是UART/SPI等外设
// 0x3000_0000 ~ 0x3FFF_FFFF, 是Flash
// 0x8000_0000 ~ 0xFFFF_FFFF, 是主存
assign seg_peripheral = (sram_addr_hold[31:28] == 4'h1);
// FIXME 使用cpu_sram_req产生组合逻辑环
assign seg_FLASH  = /*cpu_sram_req &&*/ (sram_addr_hold[31:28] == 4'h3);
assign seg_RAM    = /*cpu_sram_req &&*/ (sram_addr_hold[31] == 1'b1);
assign is_cache_req    = seg_RAM || syncing==1'b1;
assign is_uncache_req  = (seg_FLASH | seg_peripheral) && syncing==1'b0;
// assign is_cache_req    = 1'b0;
// assign is_uncache_req  = 1'b1;
`else // ENV_zemu
assign seg_peripheral = (sram_addr_hold[31:28] == 4'ha);
assign seg_FLASH      = (sram_addr_hold[31:28] == 4'h3);
assign seg_RAM        = (sram_addr_hold[31:28] == 4'h8);
assign is_cache_req    = seg_RAM || syncing==1'b1;
assign is_uncache_req  = (seg_FLASH | seg_peripheral) && syncing==1'b0;
`endif
assign narrow_trans = !seg_FLASH;

// // for reg_is_cache_req/reg_is_uncache_req
// always @(posedge clk)begin 
//     if(!resetn) begin
//         reg_is_cache_req   <=  1'b0;
//         reg_is_uncache_req <=  1'b0;
//     end
//     else if(
//             (m_state_c==IDLE && cpu_sram_req==1'b1)
//          || (m_state_c==CACHE_REQ && cache_trans_done==1'b1 && cpu_sram_req==1'b1)
//          || (m_state_c==UNCACHE_REQ && uncache_trans_done==1'b1 && cpu_sram_req==1'b1)
//            )begin
//         reg_is_cache_req   <=  cpu_is_cache_req  ;
//         reg_is_uncache_req <=  cpu_is_uncache_req;
//     end
//     else begin
//         reg_is_cache_req   <=  reg_is_cache_req  ;
//         reg_is_uncache_req <=  reg_is_uncache_req;
//     end
// end 
// assign is_cache_req    = ((m_state_c==IDLE && cpu_sram_req==1'b1)
//                         || (m_state_c==CACHE_REQ && cache_trans_done==1'b1 && cpu_sram_req==1'b1)
//                         || (m_state_c==UNCACHE_REQ && uncache_trans_done==1'b1 && cpu_sram_req==1'b1)) ? cpu_is_cache_req : reg_is_cache_req;
// assign is_uncache_req  = ((m_state_c==IDLE && cpu_sram_req==1'b1)
//                         || (m_state_c==CACHE_REQ && cache_trans_done==1'b1 && cpu_sram_req==1'b1)
//                         || (m_state_c==UNCACHE_REQ && uncache_trans_done==1'b1 && cpu_sram_req==1'b1)) ? cpu_is_uncache_req : reg_is_uncache_req;


///////////////////////////////////////
always @(posedge clk)begin 
    if(!resetn) begin
        cpu_sram_addr_r_valid <=  1'b0;
    end
    else if(cpu_sram_addr_r_valid==1'b0 && cpu_sram_req==1'b1)begin
        cpu_sram_addr_r_valid <= 1'b1;
    end
    else if(cpu_sram_addr_r_valid==1'b1 && (is_cache_req&&cache_trans_done||is_uncache_req&&uncache_trans_done) && cpu_sram_req==1'b1)begin
        cpu_sram_addr_r_valid <= 1'b1;
    end
    else if(cpu_sram_addr_r_valid==1'b1 && (is_cache_req&&cache_trans_done||is_uncache_req&&uncache_trans_done) && cpu_sram_req==1'b0)begin
        cpu_sram_addr_r_valid <= 1'b0;
    end
    else begin
        cpu_sram_addr_r_valid <= cpu_sram_addr_r_valid;
    end
end 
always @(posedge clk)begin 
    if(!resetn) begin
        cpu_sram_addr_r <= 64'b0;
    end
    else if(cpu_sram_addr_r_valid==1'b0 && cpu_sram_req==1'b1)begin
        cpu_sram_addr_r <= cpu_sram_addr;
    end
    else if(cpu_sram_addr_r_valid==1'b1 && cpu_sram_req==1'b1 && (is_cache_req&&cache_trans_done||is_uncache_req&&uncache_trans_done))begin
        cpu_sram_addr_r <= cpu_sram_addr;
    end
    else begin
        cpu_sram_addr_r <= cpu_sram_addr_r;
    end

end 
///////////////////////////////////////
// D$
assign cache_valid   = is_cache_req ? cpu_sram_req : 1'b0;
assign cache_op      = cpu_sram_wr;
assign cache_index   = cpu_sram_addr[10:4] ;
assign cache_tag     = cpu_sram_addr[31:11];
assign cache_offset  = cpu_sram_addr[3:0]  ;
assign cache_size    = cpu_sram_size;
assign cache_wstrb   = cpu_sram_wstrb;
assign cache_wdata   = cpu_sram_wdata;
// D$ axi rd
assign cache_rd_rdy    = is_cache_req ? dcache_rd_rdy    : 1'b0;
assign cache_ret_valid = is_cache_req ? dcache_ret_valid : 1'b0;
assign cache_ret_last  = is_cache_req ? dcache_ret_last  : 1'b0;
assign cache_ret_data  = is_cache_req ? dcache_ret_data  : 64'b0;
// D$ axi wr
assign cache_wr_rdy    = is_cache_req ? dcache_wr_rdy    : 1'b0;
assign cache_wr_done   = is_cache_req ? dcache_wr_done   : 1'b0;


///////////////////////////////////////
// uncache
assign uncache_req     = is_uncache_req ? cpu_sram_req : 1'b0;
assign uncache_wr      = cpu_sram_wr;
assign uncache_size    = cpu_sram_size;
assign uncache_wstrb   = cpu_sram_wstrb;
assign uncache_addr    = cpu_sram_addr;
assign uncache_wdata   = cpu_sram_wdata;
// uncache axi rd
assign uncache_rd_rdy    = is_uncache_req ? dcache_rd_rdy    : 1'b0;
assign uncache_ret_valid = is_uncache_req ? dcache_ret_valid : 1'b0;
assign uncache_ret_last  = is_uncache_req ? dcache_ret_last  : 1'b0;
assign uncache_ret_data  = is_uncache_req ? dcache_ret_data  : 64'b0;
// uncache axi wr
assign uncache_wr_rdy    = is_uncache_req ? dcache_wr_rdy    : 1'b0;
assign uncache_wr_done   = is_uncache_req ? dcache_wr_done   : 1'b0;

///////////////////////////////////////
// CPU
assign cpu_sram_addr_ok = is_cache_req ? cache_addr_ok : uncache_addr_ok;
assign cpu_sram_data_ok = is_cache_req ? cache_data_ok : uncache_data_ok;
assign cpu_sram_rdata   = is_cache_req ? cache_rdata   : uncache_rdata  ; 

///////////////////////////////////////
// AXI
assign dcache_rd_req  = is_cache_req   ?   cache_rd_req :
                        is_uncache_req ? uncache_rd_req :
                        1'b0;
assign dcache_rd_type = is_cache_req   ?   cache_rd_type :
                        is_uncache_req ? uncache_rd_type :
                        3'b0;
assign dcache_rd_addr = is_cache_req   ?   cache_rd_addr :
                        is_uncache_req ? uncache_rd_addr :
                        64'b0;
assign dcache_wr_req  = is_cache_req   ?   cache_wr_req :
                        is_uncache_req ? uncache_wr_req :
                        1'b0;
assign dcache_wr_type = is_cache_req   ?   cache_wr_type :
                        is_uncache_req ? uncache_wr_type :
                        3'b0;
assign dcache_wr_addr = is_cache_req   ?   cache_wr_addr :
                        is_uncache_req ? uncache_wr_addr :
                        64'b0;
assign dcache_wr_wstrb= is_cache_req   ?   cache_wr_wstrb :
                        is_uncache_req ? uncache_wr_wstrb :
                        8'b0;
assign dcache_wr_data = is_cache_req   ?   cache_wr_data :
                        is_uncache_req ? uncache_wr_data :
                        128'b0;

ysyx_040450_cache_unit DCache(
    .clk      (clk),
    .resetn   (resetn),

    .trans_done(cache_trans_done),
    .syncing(syncing),
    
    .valid    (cache_valid  ),
    .op       (cache_op     ),
    .index    (cache_index  ),
    .tag      (cache_tag    ),
    .offset   (cache_offset ),
    .size     (cache_size   ),
    .wstrb    (cache_wstrb  ),
    .wdata    (cache_wdata  ),
    .addr_ok  (cache_addr_ok),
    .data_ok  (cache_data_ok),
    .rdata    (cache_rdata  ),
    .sync_rvld    (sync_rvld    ),
    .sync_rrdy    (sync_rrdy    ),
    .sync_rdata_ok(sync_rdata_ok),
    .sync_rindex  (sync_rindex  ),
    .sync_rinfos  (sync_rinfos  ),
    .sync_rdatas  (sync_rdatas  ),
    `ifdef ysyx_040450_extern_cache_ram
    .io_sram0_addr (io_sram0_addr ),
    .io_sram0_cen  (io_sram0_cen  ),
    .io_sram0_wen  (io_sram0_wen  ),
    .io_sram0_wmask(io_sram0_wmask),
    .io_sram0_wdata(io_sram0_wdata),
    .io_sram0_rdata(io_sram0_rdata),
    .io_sram1_addr (io_sram1_addr ),
    .io_sram1_cen  (io_sram1_cen  ),
    .io_sram1_wen  (io_sram1_wen  ),
    .io_sram1_wmask(io_sram1_wmask),
    .io_sram1_wdata(io_sram1_wdata),
    .io_sram1_rdata(io_sram1_rdata),
    .io_sram2_addr (io_sram2_addr ),
    .io_sram2_cen  (io_sram2_cen  ),
    .io_sram2_wen  (io_sram2_wen  ),
    .io_sram2_wmask(io_sram2_wmask),
    .io_sram2_wdata(io_sram2_wdata),
    .io_sram2_rdata(io_sram2_rdata),
    .io_sram3_addr (io_sram3_addr ),
    .io_sram3_cen  (io_sram3_cen  ),
    .io_sram3_wen  (io_sram3_wen  ),
    .io_sram3_wmask(io_sram3_wmask),
    .io_sram3_wdata(io_sram3_wdata),
    .io_sram3_rdata(io_sram3_rdata),
    `endif
    .sync_wvld  (1'b0),
    .sync_wrdy  (sync_wrdy),
    .sync_windex(7'd0),
    .sync_wtagvs(44'd0),
    .sync_wdatas(256'd0),
    .rd_req   (cache_rd_req   ),
    .rd_type  (cache_rd_type  ),
    .rd_addr  (cache_rd_addr  ),
    .rd_rdy   (cache_rd_rdy   ),
    .ret_valid(cache_ret_valid),
    .ret_last (cache_ret_last ),
    .ret_data (cache_ret_data ),
    .wr_req   (cache_wr_req  ),
    .wr_type  (cache_wr_type ),
    .wr_addr  (cache_wr_addr ),
    .wr_wstrb (cache_wr_wstrb),
    .wr_data  (cache_wr_data ),
    .wr_rdy   (cache_wr_rdy  ),
    .wr_done  (cache_wr_done )
);

ysyx_040450_uncache_unit DUncache(
    .trans_done(uncache_trans_done),
    .narrow_trans(narrow_trans),
    .sram_req    (uncache_req    ),
    .sram_wr     (uncache_wr     ),
    .sram_size   (uncache_size   ),
    .sram_wstrb  (uncache_wstrb  ),
    .sram_addr   (uncache_addr   ),
    .sram_wdata  (uncache_wdata  ),
    .sram_addr_ok(uncache_addr_ok),
    .sram_data_ok(uncache_data_ok),
    .sram_rdata  (uncache_rdata  ),
    .rd_req    (uncache_rd_req   ),
    .rd_type   (uncache_rd_type  ),
    .rd_addr   (uncache_rd_addr  ),
    .rd_rdy    (uncache_rd_rdy   ),
    .ret_valid (uncache_ret_valid),
    .ret_last  (uncache_ret_last ),
    .ret_data  (uncache_ret_data ),
    .wr_req    (uncache_wr_req  ),
    .wr_type   (uncache_wr_type ),
    .wr_addr   (uncache_wr_addr ),
    .wr_wstrb  (uncache_wr_wstrb),
    .wr_data   (uncache_wr_data ),
    .wr_rdy    (uncache_wr_rdy  ),
    .wr_done   (uncache_wr_done ),
    .clk     (clk   ),
    .resetn  (resetn)
);

endmodule

module ysyx_040450_icache(
    // with CPU
    input         cpu_sram_req    ,
    input         cpu_sram_wr     ,
    input  [1 :0] cpu_sram_size   ,
    input  [7 :0] cpu_sram_wstrb  ,
    input  [63:0] cpu_sram_addr   ,
    input  [63:0] cpu_sram_wdata  ,
    output        cpu_sram_addr_ok,
    output        cpu_sram_data_ok,
    output [63:0] cpu_sram_rdata  ,
    // sync
    input          sync_wvld  , // 写请求
    output         sync_wrdy  , // 写应答
    input  [  6:0] sync_windex, // $line index
    input  [ 43:0] sync_wtagvs, // tag v 22bx2
    input  [255:0] sync_wdatas, // 两路数据
    // with axi_bridge
    output        icache_rd_req    ,
    output [ 2:0] icache_rd_type   ,
    output [63:0] icache_rd_addr   ,
    input         icache_rd_rdy    ,
    input         icache_ret_valid ,
    input         icache_ret_last  ,
    input  [63:0] icache_ret_data  ,
    `ifdef ysyx_040450_extern_cache_ram
    output[5:0]   io_sram0_addr    ,
    output        io_sram0_cen     ,
    output        io_sram0_wen     ,
    output[127:0] io_sram0_wmask   ,
    output[127:0] io_sram0_wdata   ,
    input[127:0]  io_sram0_rdata   ,
    output[5:0]   io_sram1_addr    ,
    output        io_sram1_cen     ,
    output        io_sram1_wen     ,
    output[127:0] io_sram1_wmask   ,
    output[127:0] io_sram1_wdata   ,
    input[127:0]  io_sram1_rdata   ,
    output[5:0]   io_sram2_addr    ,
    output        io_sram2_cen     ,
    output        io_sram2_wen     ,
    output[127:0] io_sram2_wmask   ,
    output[127:0] io_sram2_wdata   ,
    input[127:0]  io_sram2_rdata   ,
    output[5:0]   io_sram3_addr    ,
    output        io_sram3_cen     ,
    output        io_sram3_wen     ,
    output[127:0] io_sram3_wmask   ,
    output[127:0] io_sram3_wdata   ,
    input[127:0]  io_sram3_rdata   ,
    `endif
    // others
    input         clk,
    input         resetn
);
//=================================================================================
// Parameter declaration
//=================================================================================


//=================================================================================
// Signal declaration
//=================================================================================
reg         cpu_sram_addr_r_valid;
reg  [63:0] cpu_sram_addr_r      ; // TODO 节省资源可改为缓存cache/uncache标志
wire [63:0] sram_addr_hold;
wire              seg_FLASH;
wire              seg_RAM;
wire              is_cache_req  ;
wire              is_uncache_req;
reg               reg_is_cache_req  ;
reg               reg_is_uncache_req;
wire              narrow_trans;

// I$
wire        cache_trans_done; 
wire        syncing;
// I$ - cpu
wire        cache_valid  ;   
wire        cache_op     ;   
wire [ 6:0] cache_index  ;   
wire [20:0] cache_tag    ;   
wire [ 3:0] cache_offset ;   
wire [ 1:0] cache_size   ;   
wire [ 7:0] cache_wstrb  ;   
wire [63:0] cache_wdata  ;   
wire        cache_addr_ok;   
wire        cache_data_ok;   
wire [63:0] cache_rdata  ;   
// I$ - axi
wire        cache_rd_req   ;
wire [ 2:0] cache_rd_type  ;
wire [63:0] cache_rd_addr  ;
wire        cache_rd_rdy   ;
wire        cache_ret_valid;
wire        cache_ret_last ;
wire [63:0] cache_ret_data ;

// Uncache
wire        uncache_trans_done; 
// Uncache - cpu
wire        uncache_req    ;
wire        uncache_wr     ;
wire [1 :0] uncache_size   ;
wire [7 :0] uncache_wstrb  ;
wire [63:0] uncache_addr   ;
wire [63:0] uncache_wdata  ;
wire        uncache_addr_ok;
wire        uncache_data_ok;
wire [63:0] uncache_rdata  ;
// Uncache - axi
wire        uncache_rd_req   ;
wire [ 2:0] uncache_rd_type  ;
wire [63:0] uncache_rd_addr  ;
wire        uncache_rd_rdy   ;
wire        uncache_ret_valid;
wire        uncache_ret_last ;
wire [63:0] uncache_ret_data ;

// ===unused===
wire         sync_rrdy    ;
wire         sync_rdata_ok;
wire [ 43:0] sync_rinfos  ;
wire [255:0] sync_rdatas  ;
wire cache_wr_req  ;
wire [2:0] cache_wr_type ;
wire [63:0] cache_wr_addr ;
wire [7:0] cache_wr_wstrb;
wire [127:0] cache_wr_data ;
wire cache_wr_done ;
wire uncache_wr_req  ;
wire [2:0] uncache_wr_type ;
wire [63:0] uncache_wr_addr ;
wire [7:0] uncache_wr_wstrb;
wire [127:0] uncache_wr_data ;
wire uncache_wr_done ;

//=================================================================================
// Body
//=================================================================================
assign sram_addr_hold = cpu_sram_addr_r_valid ? cpu_sram_addr_r : cpu_sram_addr;

// 0x1000_0000 ~ 0x2FFF_FFFF, 是UART/SPI等外设
// 0x3000_0000 ~ 0x3FFF_FFFF, 是Flash
// 0x8000_0000 ~ 0xFFFF_FFFF, 是主存
// FIXME 使用cpu_sram_req产生组合逻辑环
assign seg_FLASH  = /*cpu_sram_req &&*/ (sram_addr_hold[31:28] == 4'h3);
assign seg_RAM    = /*cpu_sram_req &&*/ (sram_addr_hold[31] == 1'b1);
// FIXME 未处理不属于任何已定义区间的请求，不确定是否会导致cpu卡死
assign is_cache_req    = seg_RAM || syncing==1'b1;
assign is_uncache_req  = seg_FLASH && syncing==1'b0;
// assign is_cache_req    = 1'b0;
// assign is_uncache_req  = 1'b1;
assign narrow_trans = !seg_FLASH;

///////////////////////////////////////
always @(posedge clk)begin 
    if(!resetn) begin
        cpu_sram_addr_r_valid <=  1'b0;
    end
    else if(cpu_sram_addr_r_valid==1'b0 && cpu_sram_req==1'b1)begin
        cpu_sram_addr_r_valid <= 1'b1;
    end
    else if(cpu_sram_addr_r_valid==1'b1 && (is_cache_req&&cache_trans_done||is_uncache_req&&uncache_trans_done) && cpu_sram_req==1'b1)begin
        cpu_sram_addr_r_valid <= 1'b1;
    end
    else if(cpu_sram_addr_r_valid==1'b1 && (is_cache_req&&cache_trans_done||is_uncache_req&&uncache_trans_done) && cpu_sram_req==1'b0)begin
        cpu_sram_addr_r_valid <= 1'b0;
    end
    else begin
        cpu_sram_addr_r_valid <= cpu_sram_addr_r_valid;
    end
end 
always @(posedge clk)begin 
    if(!resetn) begin
        cpu_sram_addr_r <= 64'b0;
    end
    else if(cpu_sram_addr_r_valid==1'b0 && cpu_sram_req==1'b1)begin
        cpu_sram_addr_r <= cpu_sram_addr;
    end
    else if(cpu_sram_addr_r_valid==1'b1 && cpu_sram_req==1'b1 && (is_cache_req&&cache_trans_done||is_uncache_req&&uncache_trans_done))begin
        cpu_sram_addr_r <= cpu_sram_addr;
    end
    else begin
        cpu_sram_addr_r <= cpu_sram_addr_r;
    end
end 
always @(posedge clk)begin 
    if(!resetn) begin
        reg_is_cache_req   <= 1'b0;
        reg_is_uncache_req <= 1'b0;
    end
    else if(cpu_sram_req&&cpu_sram_addr_ok)begin
        reg_is_cache_req   <= is_cache_req  ;
        reg_is_uncache_req <= is_uncache_req;
    end
    else begin
        reg_is_cache_req   <= reg_is_cache_req  ;
        reg_is_uncache_req <= reg_is_uncache_req;
    end
end 
///////////////////////////////////////
// I$
assign cache_valid   = is_cache_req ? cpu_sram_req : 1'b0;
assign cache_op      = 1'b0;
assign cache_index   = cpu_sram_addr[10:4] ;
assign cache_tag     = cpu_sram_addr[31:11];
assign cache_offset  = cpu_sram_addr[3:0]  ;
assign cache_size    = cpu_sram_size;
assign cache_wstrb   = 8'd0;
assign cache_wdata   = 64'd0;
// I$
assign cache_rd_rdy    = is_cache_req ? icache_rd_rdy    : 1'b0;
assign cache_ret_valid = is_cache_req ? icache_ret_valid : 1'b0;
assign cache_ret_last  = is_cache_req ? icache_ret_last  : 1'b0;
assign cache_ret_data  = is_cache_req ? icache_ret_data  : 64'b0;

assign cache_wr_done = 1'b1;

///////////////////////////////////////
// uncache
assign uncache_req     = is_uncache_req ? cpu_sram_req : 1'b0;
assign uncache_wr      = 1'b0;
assign uncache_size    = cpu_sram_size;
assign uncache_wstrb   = 8'd0;
assign uncache_addr    = cpu_sram_addr;
assign uncache_wdata   = 64'd0;
// uncache
assign uncache_rd_rdy    = is_uncache_req ? icache_rd_rdy    : 1'b0;
assign uncache_ret_valid = is_uncache_req ? icache_ret_valid : 1'b0;
assign uncache_ret_last  = is_uncache_req ? icache_ret_last  : 1'b0;
assign uncache_ret_data  = is_uncache_req ? icache_ret_data  : 64'b0;

assign uncache_wr_done = 1'b1;

///////////////////////////////////////
// CPU
assign cpu_sram_addr_ok = is_cache_req ? cache_addr_ok : uncache_addr_ok;
assign cpu_sram_data_ok = is_cache_req ? cache_data_ok : uncache_data_ok;
assign cpu_sram_rdata   = is_cache_req ? cache_rdata   : uncache_rdata  ; 

///////////////////////////////////////
// AXI
assign icache_rd_req  = reg_is_cache_req   ? cache_rd_req :
                        reg_is_uncache_req ? uncache_rd_req :
                        1'b0;
assign icache_rd_type = reg_is_cache_req   ? cache_rd_type :
                        reg_is_uncache_req ? uncache_rd_type :
                        3'b0;
assign icache_rd_addr = reg_is_cache_req   ? cache_rd_addr :
                        reg_is_uncache_req ? uncache_rd_addr :
                        64'b0;

ysyx_040450_cache_unit ICache(
    .trans_done(cache_trans_done),
    .syncing(syncing),
    
    .valid    (cache_valid  ),
    .op       (cache_op     ),
    .index    (cache_index  ),
    .tag      (cache_tag    ),
    .offset   (cache_offset ),
    .size     (cache_size   ),
    .wstrb    (cache_wstrb  ),
    .wdata    (cache_wdata  ),
    .addr_ok  (cache_addr_ok),
    .data_ok  (cache_data_ok),
    .rdata    (cache_rdata  ),
    .sync_rvld    (1'b0),
    .sync_rrdy    (sync_rrdy    ),
    .sync_rdata_ok(sync_rdata_ok),
    .sync_rindex  (7'd0),
    .sync_rinfos  (sync_rinfos  ),
    .sync_rdatas  (sync_rdatas  ),
    .sync_wvld  (sync_wvld  ),
    .sync_wrdy  (sync_wrdy  ),
    .sync_windex(sync_windex),
    .sync_wtagvs(sync_wtagvs),
    .sync_wdatas(sync_wdatas),
    `ifdef ysyx_040450_extern_cache_ram
    .io_sram0_addr (io_sram0_addr ),
    .io_sram0_cen  (io_sram0_cen  ),
    .io_sram0_wen  (io_sram0_wen  ),
    .io_sram0_wmask(io_sram0_wmask),
    .io_sram0_wdata(io_sram0_wdata),
    .io_sram0_rdata(io_sram0_rdata),
    .io_sram1_addr (io_sram1_addr ),
    .io_sram1_cen  (io_sram1_cen  ),
    .io_sram1_wen  (io_sram1_wen  ),
    .io_sram1_wmask(io_sram1_wmask),
    .io_sram1_wdata(io_sram1_wdata),
    .io_sram1_rdata(io_sram1_rdata),
    .io_sram2_addr (io_sram2_addr ),
    .io_sram2_cen  (io_sram2_cen  ),
    .io_sram2_wen  (io_sram2_wen  ),
    .io_sram2_wmask(io_sram2_wmask),
    .io_sram2_wdata(io_sram2_wdata),
    .io_sram2_rdata(io_sram2_rdata),
    .io_sram3_addr (io_sram3_addr ),
    .io_sram3_cen  (io_sram3_cen  ),
    .io_sram3_wen  (io_sram3_wen  ),
    .io_sram3_wmask(io_sram3_wmask),
    .io_sram3_wdata(io_sram3_wdata),
    .io_sram3_rdata(io_sram3_rdata),
    `endif
    .rd_req   (cache_rd_req   ),
    .rd_type  (cache_rd_type  ),
    .rd_addr  (cache_rd_addr  ),
    .rd_rdy   (cache_rd_rdy   ),
    .ret_valid(cache_ret_valid),
    .ret_last (cache_ret_last ),
    .ret_data (cache_ret_data ),
    .wr_req   (cache_wr_req  ),
    .wr_type  (cache_wr_type ),
    .wr_addr  (cache_wr_addr ),
    .wr_wstrb (cache_wr_wstrb),
    .wr_data  (cache_wr_data ),
    .wr_rdy   (1'b1),
    .wr_done  (cache_wr_done ),
    .clk      (clk),
    .resetn   (resetn)
);

ysyx_040450_uncache_unit IUncache(
    .trans_done(uncache_trans_done),
    .narrow_trans(narrow_trans),
    .sram_req    (uncache_req    ),
    .sram_wr     (uncache_wr     ),
    .sram_size   (uncache_size   ),
    .sram_wstrb  (uncache_wstrb  ),
    .sram_addr   (uncache_addr   ),
    .sram_wdata  (uncache_wdata  ),
    .sram_addr_ok(uncache_addr_ok),
    .sram_data_ok(uncache_data_ok),
    .sram_rdata  (uncache_rdata  ),
    .rd_req    (uncache_rd_req   ),
    .rd_type   (uncache_rd_type  ),
    .rd_addr   (uncache_rd_addr  ),
    .rd_rdy    (uncache_rd_rdy   ),
    .ret_valid (uncache_ret_valid),
    .ret_last  (uncache_ret_last ),
    .ret_data  (uncache_ret_data ),
    .wr_req    (uncache_wr_req    ), // unused
    .wr_type   (uncache_wr_type   ),
    .wr_addr   (uncache_wr_addr   ),
    .wr_wstrb  (uncache_wr_wstrb  ),
    .wr_data   (uncache_wr_data   ),
    .wr_rdy    (1'b1),
    .wr_done   (uncache_wr_done   ),
    .clk     (clk   ),
    .resetn  (resetn)
);
endmodule
// 发起直接读写
module ysyx_040450_uncache_unit(
    output        trans_done,
    input         narrow_trans, // 1支持 0不支持
    // with CPU
    input         sram_req    ,
    input         sram_wr     ,
    input  [1 :0] sram_size   ,
    input  [7 :0] sram_wstrb  ,
    input  [63:0] sram_addr   ,
    input  [63:0] sram_wdata  ,
    output        sram_addr_ok,
    output        sram_data_ok,
    output [63:0] sram_rdata  ,
    /*with AXI              */
    output        rd_req    ,
    output [ 2:0] rd_type   ,
    output [63:0] rd_addr   ,
    input         rd_rdy    ,
    input         ret_valid ,
    input         ret_last  ,
    input  [63:0] ret_data  ,

    output        wr_req    ,
    output [ 2:0] wr_type   ,
    output [63:0] wr_addr   ,
    output [ 7:0] wr_wstrb  ,
    output [127:0]wr_data   ,
    input         wr_rdy    ,
    input         wr_done   ,
    input         clk       ,
    input         resetn
);
//=================================================================================
// Parameter declaration
//=================================================================================


//=================================================================================
// Signal declaration
//=================================================================================
// request buffer
reg        reg_narrow_trans;
reg        reg_sram_wr   ;
reg [1 :0] reg_sram_size ;
reg [7 :0] reg_sram_wstrb;
reg [63:0] reg_sram_addr ;
reg [63:0] reg_sram_wdata;

//=================================================================================
// Body
//=================================================================================
/*MAIN FSM                  */
parameter IDLE    = 3'b001;
parameter REQUEST = 3'b010;
parameter TRANS   = 3'b100;
reg [2:0] m_state_c;    //main FSM current state
reg [2:0] m_state_n;    //main FSM next state

always @(posedge clk)begin 
    if(!resetn) m_state_c <= IDLE;
    else m_state_c <= m_state_n;
end 

always @(*)begin 
    case(m_state_c)
        IDLE:begin 
            if(sram_req==1'b1)begin 
                m_state_n = REQUEST;
            end
            else begin  //else if(valid==1'b0)
                m_state_n = IDLE;
            end 
        end
        REQUEST:begin 
            if(reg_sram_wr==1'b1)begin // write request
                if(wr_rdy==1'b0)begin 
                    m_state_n = REQUEST;
                end 
                else if(wr_rdy==1'b1)begin
                    m_state_n = TRANS;
                end //no else
            end
            else if(reg_sram_wr==1'b0)begin // read request
                if(rd_rdy==1'b0)begin 
                    m_state_n = REQUEST;
                end 
                else if(rd_rdy==1'b1)begin
                    m_state_n = TRANS;
                end //no else
            end //no else
        end 
        TRANS:begin 
            if(reg_sram_wr==1'b1)begin // write request
                if(wr_done==1'b0)begin
                    m_state_n = TRANS;
                end 
                else if(wr_done==1'b1)begin 
                    m_state_n = IDLE;
                end 
            end
            else if(reg_sram_wr==1'b0)begin // read request
                if(ret_valid==1'b1 && ret_last==1'b1)begin 
                    m_state_n = IDLE;
                end 
                else begin
                    m_state_n = TRANS;
                end 
            end //no else
        end 
        default: m_state_n = IDLE;
    endcase
end 

//  request buffer
always @(posedge clk) begin
    if(m_state_c==IDLE && sram_req==1'b1) begin
        reg_narrow_trans <= narrow_trans;
        reg_sram_wr    <= sram_wr   ;
        reg_sram_size  <= sram_size ;
        reg_sram_wstrb <= sram_wstrb;
        reg_sram_addr  <= sram_addr ;
        reg_sram_wdata <= sram_wdata;
    end
    else begin
        reg_narrow_trans <= reg_narrow_trans;
        reg_sram_wr    <= reg_sram_wr   ;
        reg_sram_size  <= reg_sram_size ;
        reg_sram_wstrb <= reg_sram_wstrb;
        reg_sram_addr  <= reg_sram_addr ;
        reg_sram_wdata <= reg_sram_wdata;
    end
end
// 数据选择，针对不支持窄传输的flash
wire [2:0]  sel_data = reg_sram_addr[2:0];
wire [7:0]  load_byte;
wire [15:0] load_halfword;
wire [31:0] load_word;
wire [63:0] load_res;
ysyx_040450_MuxKey #(8, 3, 8) i_load_byte_sel (load_byte, sel_data[2:0], {
    3'b000, ret_data[7:0],
    3'b001, ret_data[15:8],
    3'b010, ret_data[23:16],
    3'b011, ret_data[31:24],
    3'b100, ret_data[39:32],
    3'b101, ret_data[47:40],
    3'b110, ret_data[55:48],
    3'b111, ret_data[63:56]
});
ysyx_040450_MuxKey #(4, 2, 16) i_load_halfword_sel (load_halfword, sel_data[2:1], {
    2'b00, ret_data[15:0],
    2'b01, ret_data[31:16],
    2'b10, ret_data[47:32],
    2'b11, ret_data[63:48]
});
ysyx_040450_MuxKey #(2, 1, 32) i_load_word_sel (load_word, sel_data[2], {
    1'b0, ret_data[31:0],
    1'b1, ret_data[63:32]
});
ysyx_040450_MuxKey #(4, 2, 64) i_load_data_sel (load_res, reg_sram_size, {
    2'b00, {{56{1'b0}}, load_byte},
    2'b01, {{48{1'b0}}, load_halfword},
    2'b10, {{32{1'b0}}, load_word},
    2'b11, ret_data
});
// CPU
assign sram_addr_ok = m_state_c==IDLE;
assign sram_data_ok = (m_state_c==TRANS && reg_sram_wr==1'b1 && wr_done==1'b1)
                   || (m_state_c==TRANS && reg_sram_wr==1'b0 && ret_valid==1'b1 && ret_last==1'b1);
assign sram_rdata   = reg_narrow_trans ? ret_data : load_res;
assign trans_done = sram_data_ok;
// AXI - rd
assign rd_req  = m_state_c==REQUEST && reg_sram_wr==1'b0;
assign rd_type[2] = 1'b0;
assign rd_type[1:0] = reg_sram_size;
assign rd_addr = reg_sram_addr;
// AXI - wr
assign wr_req   = m_state_c==REQUEST && reg_sram_wr==1'b1;
assign wr_type[2] = 1'b0;
assign wr_type[1:0] = reg_sram_size;
assign wr_addr  = reg_sram_addr;
assign wr_wstrb = reg_sram_wstrb;
assign wr_data  = {64'd0, reg_sram_wdata};

endmodule

module ysyx_040450_if_stage(
    input                          clk            ,
    input                          resetn         ,
    //allwoin
    input                          ds_allowin     ,
    //brbus
    input  [`ysyx_040450_BR_BUS_WD       -1:0] br_bus         ,
    input                          br_leaving     ,
    //jmpbus
    input  [`ysyx_040450_JMP_BUS_WD      -1:0] jmp_bus        ,
    input                                        jmp_leaving    ,
    //to ds
    output                         fs_to_ds_valid ,
    output [`ysyx_040450_FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus   ,
    // inst sram interface
    // output        inst_sram_en   ,
    // output [ 7:0] inst_sram_wen  ,
    // output [63:0] inst_sram_addr ,
    // output [63:0] inst_sram_wdata,
    // input  [63:0] inst_sram_rdata
    output        inst_sram_req    ,
    output        inst_sram_wr     ,
    output [1 :0] inst_sram_size   ,
    output [7 :0] inst_sram_wstrb  ,
    output [63:0] inst_sram_addr   ,
    output [63:0] inst_sram_wdata  ,
    input         inst_sram_addr_ok,
    input         inst_sram_data_ok,
    input  [63:0] inst_sram_rdata
);

reg         fs_valid;
wire        fs_ready_go;
wire        fs_allowin;
wire        pre_fs_ready_go;
wire        to_fs_valid;

wire fs_inst_sysjmp;

wire [63:0] fs_snpc;
wire [63:0] nextpc;

// 实际目前branch不需要stall，分支无效时fs_to_ds_valid将为低则指令无效
// 但这会导致分支是否有效都从存储器中读取指令，添加分支预测后应去除 -> 但是解码前应该都会发出下一条指令的req
wire         br_stall; 
wire         irq_taken;
wire         br_taken;
wire [63:0]  br_target;
reg [`ysyx_040450_BR_BUS_WD-1:0] br_bus_r; // 暂存br_bus
reg br_bus_r_valid; // 暂存br_bus的有效标志
// reg bd_done;
assign {br_stall,irq_taken,br_taken,br_target} = br_bus_r_valid ? br_bus_r : br_bus;

reg [`ysyx_040450_JMP_BUS_WD-1:0] jmp_bus_r; // 暂存jmp_bus
reg jmp_bus_r_valid; // 暂存jmp_bus的有效标志
wire        jmp_stall; // FIXME 未使用
wire        jmp_taken;
wire [63:0] jmp_target;
assign {jmp_stall,jmp_taken,jmp_target} = jmp_bus_r_valid ? jmp_bus_r : jmp_bus;


wire [31:0] fs_inst;
reg  [31:0] fs_inst_r;
reg         fs_inst_r_valid;
reg  [63:0] fs_pc;
assign fs_to_ds_bus = {fs_inst ,
                       fs_snpc ,
                       fs_pc   };

// pre-IF stage
assign pre_fs_ready_go = (inst_sram_req & inst_sram_addr_ok)
                        && !br_stall && !fs_inst_sysjmp;
assign to_fs_valid  = resetn && pre_fs_ready_go;
assign fs_snpc      = fs_pc + 4;
assign nextpc     = (jmp_bus_r_valid && jmp_taken) ? jmp_target :
                    jmp_taken ? jmp_target :
                    (br_bus_r_valid && br_taken) ? br_target :
                    br_taken ? br_target :
                    fs_snpc; 

//br_bus buffer
always @(posedge clk) begin
    if(!resetn) begin
        br_bus_r <= {`ysyx_040450_BR_BUS_WD{1'b0}};
        br_bus_r_valid <= 1'b0;
    end
    else if(nextpc==br_target && pre_fs_ready_go==1'b1 && fs_allowin==1'b1) begin
        br_bus_r <= br_bus_r;
        br_bus_r_valid <= 1'b0;
    end
    else if(br_leaving==1'b1) begin
        br_bus_r <= br_bus;
        br_bus_r_valid <= 1'b1;
    end
    else begin
        br_bus_r <= br_bus_r;
        br_bus_r_valid <= br_bus_r_valid;
    end
end

//jmp_bus buffer
always @(posedge clk) begin
    if(!resetn) begin
        jmp_bus_r <= {`ysyx_040450_JMP_BUS_WD{1'b0}};
        jmp_bus_r_valid <= 1'b0;
    end
    else if(nextpc==jmp_target && pre_fs_ready_go==1'b1 && fs_allowin==1'b1) begin
        jmp_bus_r <= jmp_bus_r;
        jmp_bus_r_valid <= 1'b0;
    end
    else if(jmp_leaving==1'b1) begin
        jmp_bus_r <= jmp_bus;
        jmp_bus_r_valid <= 1'b1;
    end
    else begin
        jmp_bus_r <= jmp_bus_r;
        jmp_bus_r_valid <= jmp_bus_r_valid;
    end
end

// IF stage
assign fs_ready_go    = (inst_sram_data_ok || fs_inst_r_valid);//1'b1;//!br_stall;//!br_taken;
assign fs_allowin     = !fs_valid || fs_ready_go && ds_allowin;
// FIXME 逻辑错误
assign fs_to_ds_valid =  fs_valid && fs_ready_go && !irq_taken && !br_taken && !jmp_taken; // 此处br_taken相当于插入一周期bubble
always @(posedge clk) begin
    if (!resetn) begin
        fs_valid <= 1'b0;
    end
    else if (fs_allowin) begin
        fs_valid <= to_fs_valid;
    end

    if (!resetn) begin
        fs_pc <= `ysyx_040450_PC_INITIAL;  //trick: to make nextpc be 0x80000000 during reset 
    end
    else if (to_fs_valid && fs_allowin) begin
        fs_pc <= nextpc;
    end
end

always @(posedge clk) begin
    if (!resetn) begin
        fs_inst_r <= 32'h0;
        fs_inst_r_valid <= 1'b0;
    end
    else if (inst_sram_data_ok && !ds_allowin) begin
        fs_inst_r <= inst_sram_rdata[31:0];
        fs_inst_r_valid <= 1'b1;
        // fs_inst <= nextpc[2] ? inst_sram_rdata[63:32] : 
        //                     inst_sram_rdata[31:0];
    end
    else if(fs_ready_go && ds_allowin) begin
        fs_inst_r <= fs_inst_r;
        fs_inst_r_valid <= 1'b0;
    end
    else begin
        fs_inst_r <= fs_inst_r;
        fs_inst_r_valid <= fs_inst_r_valid;
    end
end
assign fs_inst = fs_inst_r_valid ? fs_inst_r :
                 inst_sram_data_ok ? inst_sram_rdata[31:0] : // FIXME inst_sram_rdata -> 32bits
                 32'd0;

// stall时转移计算为完成，不应发出请求
// FIXME inst_sram_req wire->reg 避免组合逻辑环
assign inst_sram_req     = (br_stall|jmp_stall|fs_inst_sysjmp) ? 1'b0 : fs_allowin; //to_fs_valid && fs_allowin;
assign inst_sram_wr      = 1'b0;
assign inst_sram_size    = 2'b10;
assign inst_sram_wstrb   = 8'h00;
// assign inst_sram_addr    = {nextpc[63:3], 3'b000};
assign inst_sram_addr    = {nextpc[63:2], 2'b00};
assign inst_sram_wdata   = 64'b0;

///////////////////
// pre decode
// ecall, ebreak, mret, fencei -> es阶段才完成npc获取
// fs_inst_sysjmp/br_stall 用于在接收到上述指令时暂停发送新的指令请求
assign fs_inst_sysjmp = (fs_inst[19:0] == 20'h00073 // ecall, ebreak, mret
                      || fs_inst[19:0] == 20'h0100f // fencei
                      ) && fs_valid;

endmodule

module ysyx_040450_id_stage(
    //allowin
    input                          es_allowin    ,
    output                         ds_allowin    ,
    //from fs
    input                          fs_to_ds_valid,
    input  [`ysyx_040450_FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus  ,
    //to es
    output                         ds_to_es_valid,
    output [`ysyx_040450_DS_TO_ES_BUS_WD -1:0] ds_to_es_bus  ,
    //to fs
    output [`ysyx_040450_BR_BUS_WD       -1:0] br_bus        ,
    output                         br_leaving    ,
    //to rf: for write back
    input  [`ysyx_040450_WS_TO_RF_BUS_WD -1:0] ws_to_rf_bus  ,
    //forward from es
    input  [`ysyx_040450_ES_FWD_BUS_WD   -1:0] es_to_ds_fwd_i,
    //forward from ms
    input  [`ysyx_040450_MS_FWD_BUS_WD   -1:0] ms_to_ds_fwd_i,
    input       excp_irq_valid,
    output      excp_irq_ready,
    input [2:0] excp_irq_type ,
    `ifdef ysyx_040450_ysyxSoc_DIFF
	output wire [63:0] rf_regs[0 : 31],
    `endif
    input                          clk           ,
    input                          resetn        
);

reg         ds_valid   ;
wire        ds_ready_go;

// wire [63                 :0] fs_pc;
reg  [`ysyx_040450_FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus_r;
// assign fs_pc = fs_to_ds_bus[63:0]; // 相当于snpc

wire [31:0] ds_inst;
wire [63:0] ds_pc  ;
wire [31:0] ds_inst_r;
wire [63:0] ds_pc_r  ;
wire [63:0] ds_snpc;
reg  [63:0] ds_dnpc;
assign {ds_inst_r,
        ds_snpc  ,
        ds_pc_r  } = fs_to_ds_bus_r;

// 发生中断使用自定义指令，pc设为下一条指令地址
assign ds_inst = excp_irq_valid ? {25'h0,5'h1f,2'b11} : ds_inst_r;
assign ds_pc   = (excp_irq_valid && !ds_valid) ? ds_dnpc : ds_pc_r;

wire        wb_rf_we   ;
wire [ 4:0] wb_rf_waddr;
wire [63:0] wb_rf_wdata;
assign {wb_rf_we   ,  //69:69
        wb_rf_waddr,  //68:64
        wb_rf_wdata   //63:0
       } = ws_to_rf_bus;

wire        es_fwd_is_LOAD ;
wire        es_fwd_rf_we   ;
wire [ 4:0] es_fwd_rf_waddr;
wire [63:0] es_fwd_rf_wdata;
assign {es_fwd_is_LOAD ,
        es_fwd_rf_we   ,  //69:69
        es_fwd_rf_waddr,  //68:64
        es_fwd_rf_wdata   //63:0
       } = es_to_ds_fwd_i;

wire        ms_fwd_is_LOAD ;
wire        ms_fwd_rf_we   ;
wire [ 4:0] ms_fwd_rf_waddr;
wire [63:0] ms_fwd_rf_wdata;
assign {ms_fwd_is_LOAD ,
        ms_fwd_rf_we   ,  //69:69
        ms_fwd_rf_waddr,  //68:64
        ms_fwd_rf_wdata   //63:0
       } = ms_to_ds_fwd_i;

wire        br_stall;
wire        irq_taken;
wire        br_taken;
wire [63:0] br_target;

wire is_mem_op;
wire mem_we;
wire [1:0] mem_size;
wire ds_rf_we;
wire is_mdr_op;
wire is_word_op;
wire [3:0] alu_op;
// wire        src1_is_rs1;
wire        src1_is_pc;
// wire        src2_is_rs2;
wire        src2_is_imm;
wire [63:0] immSext;

wire op_1_0_11;
wire [ 4:0] opcode5;
wire [ 4:0] rd;
wire [ 2:0] funct3;
wire [ 4:0] rs1;
wire [ 4:0] rs2;
wire [ 6:0] funct7;
wire [31:0] opcode5_d;
wire [31:0] rd_d;
wire [ 7:0] funct3_d;
wire [31:0] rs1_d;
wire [31:0] rs2_d;
wire [127:0] funct7_d;

wire [ 5:0] funct6;
wire funct6_000000;
wire funct6_010000;
wire [ 3:0] funct4;
// wire [63:0] funct6_d;

wire [63:0] immI;
wire [63:0] immS;
wire [63:0] immB;
wire [63:0] immU;
wire [63:0] immJ;
wire [11:0] csrid;

wire        inst_lui;
wire        inst_auipc;
wire        inst_jal;
wire        inst_jalr;
wire        inst_BRANCH;
// wire        inst_beq;
// wire        inst_bne;
// wire        inst_blt;
// wire        inst_bge;
// wire        inst_bltu;
// wire        inst_bgeu;
wire        inst_LOAD;
// wire        inst_lb;
// wire        inst_lh;
// wire        inst_lw;
// wire        inst_ld;
// wire        inst_lbu;
// wire        inst_lhu;
// wire        inst_lwu;
wire        inst_STORE;
// wire        inst_sb;
// wire        inst_sh;
// wire        inst_sw;
// wire        inst_sd;
wire        inst_OP;
// wire        inst_add;
// wire        inst_sub;
// wire        inst_sll;
// wire        inst_slt;
// wire        inst_sltu;
// wire        inst_xor;
// wire        inst_srl;
// wire        inst_sra;
// wire        inst_or;
// wire        inst_and;
// wire        inst_mul;
// wire        inst_mulh;
// wire        inst_mulhsu;
// wire        inst_mulhu;
// wire        inst_div;
// wire        inst_divu;
// wire        inst_rem;
// wire        inst_remu;
wire        inst_OP_IMM; // 双字立即数运算
// wire        inst_addi;
// wire        inst_slli;
// wire        inst_slti;
// wire        inst_sltiu;
// wire        inst_xori;
// wire        inst_srli;
// wire        inst_srai;
// wire        inst_ori;
// wire        inst_andi;
wire        inst_OP_IMM_32; // 单字立即数运算
// wire        inst_addiw;
// wire        inst_slliw;
// wire        inst_srliw;
// wire        inst_sraiw;
wire        inst_OP_32; // 单字寄存器运算
// wire        inst_addw;
// wire        inst_subw;
// wire        inst_sllw;
// wire        inst_srlw;
// wire        inst_sraw;
// wire        inst_mulw;
// wire        inst_divw;
// wire        inst_remw;
// wire        inst_remuw;
// wire        inst_fence;
wire        inst_fencei;
wire        inst_irq; // custom
wire        inst_ecall;
wire        inst_ebreak;
wire        inst_mret;
wire        inst_CSRRXX;
// wire        inst_csrrw;
// wire        inst_csrrs;
// wire        inst_csrrc;
// wire        inst_csrrwi;
// wire        inst_csrrsi;
// wire        inst_csrrci;

`ifdef ysyx_040450_OPT_FIT_YSYX3
wire        inst_0x7b; // $write
`endif

wire inst_OP_alu     ;
wire inst_OP_mdr     ;
wire inst_OP_32_alu  ;
wire inst_OP_32_mdr  ;

wire inst_slli       ;
wire inst_srli       ;
wire inst_srai       ;

wire inst_addiw      ;

wire es_fwd_valid_a;
wire es_fwd_valid_b;
wire ms_fwd_valid_a;
wire ms_fwd_valid_b;
wire ws_fwd_valid_a;
wire ws_fwd_valid_b;
wire [63:0] rf_rdata1;
wire [63:0] rf_rdata2;
wire [63:0] rs1_data;
wire [63:0] rs2_data;

assign br_bus       = {br_stall,irq_taken,br_taken,br_target};

assign ds_to_es_bus = {ds_inst      ,  // 32
                       ds_snpc      ,  // 64
                       inst_jal     ,  //135:124 1
                       inst_jalr    ,  //135:124 1
                       inst_fencei  ,  // 1
                       inst_irq     ,  // 1
                       inst_ecall   ,  // 1
                       inst_ebreak  ,  // 1
                       `ifdef ysyx_040450_OPT_FIT_YSYX3
                       inst_0x7b    ,  // 1
                       `endif
                       inst_mret    ,  // 1
                       inst_CSRRXX  ,
                       is_mem_op    ,  //135:275 1
                       mem_we       ,  //135:274 1
                       mem_size     ,  //273:272 2
                       ds_rf_we     ,  //135:271 1
                       rd           ,  //270:266 5
                       is_mdr_op    ,  //123:265 1
                       is_word_op   ,  //118:264 1
                       alu_op       ,  //263:260 4
                    //    src1_is_rs1  ,  //122:259 1
                       src1_is_pc   ,  //121:258 1
                    //    src2_is_rs2  ,  //120:257 1
                       src2_is_imm  ,  //119:256 1
                       immSext      ,  //255:96  64
                       rs1_data     ,  //95 :64  64
                       rs2_data     ,  //127:64  64
                       ds_pc           //63 :0   64
                      };

assign ds_ready_go    = ((ms_fwd_valid_a | ms_fwd_valid_b) & ms_fwd_is_LOAD) ? 1'b0 :
                        ((es_fwd_valid_a | es_fwd_valid_b) & es_fwd_is_LOAD) ? 1'b0 :
                        1'b1;
assign ds_allowin     = !ds_valid || ds_ready_go && es_allowin;
assign ds_to_es_valid = ds_valid && ds_ready_go;
always @(posedge clk) begin
    if (!resetn) begin
        ds_valid <= 1'b0;
    end
    else if (ds_allowin) begin
        ds_valid <= fs_to_ds_valid;
    end

    if (fs_to_ds_valid && ds_allowin) begin
        fs_to_ds_bus_r <= fs_to_ds_bus;
    end
end

assign opcode5 = ds_inst[6:2];
assign rd = ds_inst[11:7];
assign funct3  = ds_inst[14:12];
assign rs1 = ds_inst[19:15];
assign rs2 = ds_inst[24:20];
assign funct7  = ds_inst[31:25];

assign funct6  = ds_inst[31:26];
assign funct6_000000  = funct6==6'b000000;
assign funct6_010000  = funct6==6'b010000;
assign funct4 = {ds_inst[14:12],ds_inst[30]};

assign immI = {{52{ds_inst[31]}},ds_inst[31:20]};
assign immS = {{52{ds_inst[31]}},ds_inst[31:25],ds_inst[11:7]};
assign immB = {{51{ds_inst[31]}},ds_inst[31],ds_inst[7],ds_inst[30:25],ds_inst[11:8],1'b0};
assign immU = {{32{ds_inst[31]}},ds_inst[31:12],12'd0};
assign immJ = {{43{ds_inst[31]}},ds_inst[31],ds_inst[19:12],ds_inst[20],ds_inst[30:21],1'b0};
assign csrid = ds_inst[31:20];

assign op_1_0_11 = ds_inst[1:0] == 2'b11;
ysyx_040450_decoder_5_32 u_dec0(.in(opcode5  ), .out(opcode5_d  ));
ysyx_040450_decoder_5_32 u_dec1(.in(rd  ), .out(rd_d  ));
ysyx_040450_decoder_3_8  u_dec2(.in(funct3  ), .out(funct3_d  ));
ysyx_040450_decoder_5_32 u_dec3(.in(rs1  ), .out(rs1_d  ));
ysyx_040450_decoder_5_32 u_dec4(.in(rs2  ), .out(rs2_d  ));
// ysyx_040450_decoder_6_64 u_dec5(.in(funct6), .out(funct6_d));
ysyx_040450_decoder_7_128 u_dec6(.in(funct7), .out(funct7_d));

assign inst_lui        = op_1_0_11 & opcode5_d[5'h0d];
assign inst_auipc      = op_1_0_11 & opcode5_d[5'h05];
assign inst_jal        = op_1_0_11 & opcode5_d[5'h1b];
assign inst_jalr       = op_1_0_11 & opcode5_d[5'h19];
assign inst_BRANCH     = op_1_0_11 & opcode5_d[5'h18];
assign inst_LOAD       = op_1_0_11 & opcode5_d[5'h00];
assign inst_STORE      = op_1_0_11 & opcode5_d[5'h08];
assign inst_OP         = op_1_0_11 & opcode5_d[5'h0c];
assign inst_OP_IMM     = op_1_0_11 & opcode5_d[5'h04];
assign inst_OP_IMM_32  = op_1_0_11 & opcode5_d[5'h06];
assign inst_OP_32      = op_1_0_11 & opcode5_d[5'h0e];

assign inst_OP_alu     = inst_OP    & ~funct7_d[7'h01];
assign inst_OP_mdr     = inst_OP    &  funct7_d[7'h01];
assign inst_OP_32_alu  = inst_OP_32 & ~funct7_d[7'h01];
assign inst_OP_32_mdr  = inst_OP_32 &  funct7_d[7'h01];

assign inst_slli       = inst_OP_IMM & funct3_d[3'h0] & funct6_000000;
assign inst_srli       = inst_OP_IMM & funct3_d[3'h5] & funct6_000000;
assign inst_srai       = inst_OP_IMM & funct3_d[3'h5] & funct6_010000;

assign inst_addiw      = inst_OP_IMM_32 & funct3_d[3'h0];

// assign inst_fence  = op_1_0_11 & opcode5_d[5'h03] & funct3_d[3'h0] & rd_d[5'h00] & rs1_d[5'h00] & (csrid[11:8] == 4'h0);
assign inst_fencei = op_1_0_11 & opcode5_d[5'h03] & funct3_d[3'h1] & rd_d[5'h00] & rs1_d[5'h00] & (csrid == 12'h000);
assign inst_irq    = op_1_0_11 & opcode5_d[5'h1f] & funct3_d[3'h0] & rd_d[5'h00] & rs1_d[5'h00] & rs2_d[5'h00] & funct7_d[7'h00];
assign inst_ecall  = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h0] & rd_d[5'h00] & rs1_d[5'h00] & rs2_d[5'h00] & funct7_d[7'h00];//(csrid == 12'h000);
`ifdef ysyx_040450_OPT_FIT_YSYX3
assign inst_ebreak = (op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h0] & rd_d[5'h00] & rs1_d[5'h00] & rs2_d[5'h01] & funct7_d[7'h00])|(op_1_0_11 & opcode5_d[5'h1a]);
`else
assign inst_ebreak = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h0] & rd_d[5'h00] & rs1_d[5'h00] & rs2_d[5'h01] & funct7_d[7'h00];//(csrid == 12'h001);
`endif
assign inst_mret   = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h0] & rd_d[5'h00] & rs1_d[5'h00] & rs2_d[5'h02] & funct7_d[7'h18];//(csrid == 12'h302);
assign inst_CSRRXX = op_1_0_11 & opcode5_d[5'h1c] & ~funct3_d[3'h0];
// assign inst_csrrw  = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h1];
// assign inst_csrrs  = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h2];
// assign inst_csrrc  = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h3];
// assign inst_csrrwi = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h5];
// assign inst_csrrsi = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h6];
// assign inst_csrrci = op_1_0_11 & opcode5_d[5'h1c] & funct3_d[3'h7];

`ifdef ysyx_040450_OPT_FIT_YSYX3
assign inst_0x7b = (op_1_0_11 & opcode5_d[5'h1e]);
`endif
// 复用alu_op传递irq类型
assign alu_op = (inst_irq) ? {1'b0, excp_irq_type} :
                (inst_auipc | inst_jal | inst_BRANCH | inst_LOAD | inst_STORE) ? `ysyx_040450_ALU_OP_ADD :
                (inst_lui) ? `ysyx_040450_ALU_OP_IMM :
                (inst_OP_alu | inst_slli | inst_srli | inst_srai | (inst_OP_IMM_32 & ~inst_addiw) | inst_OP_32_alu) ? funct4 :
                {funct3, 1'b0};

assign immSext = (inst_lui | inst_auipc) ? immU :
                 (inst_jal)              ? immJ :
                 (inst_BRANCH) ? immB :
                 (inst_STORE) ? immS :
                 /* jalr load op-imm[-32] */ immI;

// assign src1_is_rs1  = inst_jalr | inst_LOAD | inst_STORE | inst_OP | inst_OP_32 | inst_OP_IMM | inst_OP_IMM_32;
assign src1_is_pc   = inst_auipc | inst_jal | inst_BRANCH;
assign src2_is_imm  = inst_lui | inst_auipc | inst_jal | inst_jalr | inst_BRANCH | inst_LOAD | inst_STORE | inst_OP_IMM | inst_OP_IMM_32;
// assign src2_is_rs2  = inst_OP | inst_OP_32;
// TODO 当目标寄存器为0时，不使能 -> 同时可以移除前递的判断
assign ds_rf_we     = ~inst_BRANCH 
                    & ~inst_STORE 
                    & ~inst_ebreak 
                    & ~inst_ecall 
                    & ~inst_mret 
                    & ~inst_irq 
                    `ifdef ysyx_040450_OPT_FIT_YSYX3
                    & ~inst_0x7b 
                    `endif
                    & ~inst_fencei;
assign is_mem_op    = (inst_LOAD | inst_STORE);
assign mem_we       = inst_STORE;
assign mem_size     = funct3[1:0];
assign is_word_op   = (inst_OP_32 | inst_OP_IMM_32);
assign is_mdr_op    = (inst_OP_mdr | inst_OP_32_mdr);

assign es_fwd_valid_a = !rs1_d[5'h00] & es_fwd_rf_we & (es_fwd_rf_waddr == rs1);
assign es_fwd_valid_b = !rs2_d[5'h00] & es_fwd_rf_we & (es_fwd_rf_waddr == rs2);
assign ms_fwd_valid_a = !rs1_d[5'h00] & ms_fwd_rf_we & (ms_fwd_rf_waddr == rs1);
assign ms_fwd_valid_b = !rs2_d[5'h00] & ms_fwd_rf_we & (ms_fwd_rf_waddr == rs2);
assign ws_fwd_valid_a = !rs1_d[5'h00] & wb_rf_we & (wb_rf_waddr == rs1);
assign ws_fwd_valid_b = !rs2_d[5'h00] & wb_rf_we & (wb_rf_waddr == rs2);

assign rs1_data   = es_fwd_valid_a ? es_fwd_rf_wdata :
                    ms_fwd_valid_a ? ms_fwd_rf_wdata :
                    ws_fwd_valid_a ? wb_rf_wdata :
                    rf_rdata1;
assign rs2_data   = es_fwd_valid_b ? es_fwd_rf_wdata :
                    ms_fwd_valid_b ? ms_fwd_rf_wdata :
                    ws_fwd_valid_b ? wb_rf_wdata :
                    rf_rdata2;

ysyx_040450_regfile #(5, 64) u_regfile(
    .clk     (clk      ),
    `ifdef ysyx_040450_ysyxSoc_DIFF
	.rf_regs(rf_regs),
    `endif
    .raddr_a (rs1),
    .rdata_a (rf_rdata1),
    .raddr_b (rs2),
    .rdata_b (rf_rdata2),
    .wen     (wb_rf_we    ),
    .waddr   (wb_rf_waddr ),
    .wdata   (wb_rf_wdata )
    );

wire branch_valid; // 条件跳转条件成立
ysyx_040450_blu i_BLU (
    .in_a(rs1_data),
    .in_b(rs2_data),
    .funct3(funct3),
    .result(branch_valid)
);

assign br_leaving = br_taken && es_allowin;
assign br_stall  = (    inst_ecall
                    ||  inst_ebreak
                    ||  inst_mret
                    ||  inst_fencei
                    ||  es_fwd_valid_a && es_fwd_is_LOAD // Load-to-Branch
                   ) && ds_valid && ds_ready_go; // 转移计算未完成
assign irq_taken = inst_irq && ds_valid && ds_ready_go;
assign br_taken   = (   inst_BRANCH && branch_valid
                     || inst_jal
                     || inst_jalr
                    ) && ds_valid && ds_ready_go;
assign br_target  = (inst_jalr) ? (rs1_data+immSext)&64'hffffffff_fffffffe :
                    /*inst_jal/inst_BRANCH*/ ds_pc+immSext;
// fs_pc + immSext; 

// exception
assign excp_irq_ready = ds_to_es_valid && es_allowin;
// dnpc
always @(posedge clk) begin
    if(!resetn)
        ds_dnpc <= 64'h80000000;
    else if(ds_valid && ds_ready_go && es_allowin) begin
        ds_dnpc <= (br_taken) ? br_target : ds_snpc;
    end else
        ds_dnpc <= ds_dnpc;
end

`ifdef ysyx_040450_ZEMU_DIFF
import "DPI-C" function void rtl2emu_issue(input bit valid, input longint next_pc, input int next_inst);
always @(*) begin
        rtl2emu_issue(ds_to_es_valid&&es_allowin, ds_pc, ds_inst);
end
`endif

endmodule

module ysyx_040450_exe_stage(
    //allowin
    input                          ms_allowin    ,
    output                         es_allowin    ,
    //from ds
    input                          ds_to_es_valid,
    input  [`ysyx_040450_DS_TO_ES_BUS_WD -1:0] ds_to_es_bus  ,
    //to ms
    output                         es_to_ms_valid,
    output [`ysyx_040450_ES_TO_MS_BUS_WD -1:0] es_to_ms_bus  ,
    //to fs
    output                                        jmp_leaving  ,
    output [`ysyx_040450_JMP_BUS_WD       -1:0] jmp_bus      ,
    // forward to ds
    output [`ysyx_040450_ES_FWD_BUS_WD   -1:0] es_fwd_o      ,
    // with csr
    input         plic_ext_irq , // 优先级递减
    input         clint_sft_irq,
    input         clint_tmr_irq,
    output        csr_status_MIE_r,
    output        csr_mie_MEIE_r  ,
    output        csr_mie_MTIE_r  ,
    output        csr_mie_MSIE_r  ,
    output        es_inst_env,
    // cache sync
    output fencei_req,
    input  fencei_ack,

    // data sram interface
    // output        data_sram_en   ,
    // output [ 3:0] data_sram_wen  ,
    // output [31:0] data_sram_addr ,
    // output [31:0] data_sram_wdata
    output         data_sram_req    ,
    output         data_sram_wr     ,
    output [1 :0]  data_sram_size   ,
    output [7 :0]  data_sram_wstrb  ,
    output [63:0]  data_sram_addr   ,
    output [63:0]  data_sram_wdata  ,
    input          data_sram_addr_ok,
    `ifdef ysyx_040450_ysyxSoc_DIFF
    // output [`ysyx_040450_csr2emu_BUS_WD-1:0] csr2emu_bus,
    output [`ysyx_040450_diff_es_BUS_WD-1:0] diff_es_bus,
    `endif
    input                          clk           ,
    input                          resetn        
);

reg         es_valid      ;
wire        es_ready_go   ;

reg  [`ysyx_040450_DS_TO_ES_BUS_WD -1:0] ds_to_es_bus_r;
wire [31:0] es_inst       ;
wire [63:0] es_snpc       ;
wire        es_inst_jal   ;
wire        es_inst_jalr  ;
wire        es_inst_fencei;
wire        es_inst_irq   ;
wire        es_inst_ecall ;
wire        es_inst_ebreak;
`ifdef ysyx_040450_OPT_FIT_YSYX3
wire        es_inst_0x7b  ;
`endif
wire        es_inst_mret  ;
wire        es_is_csr_op  ;
wire        es_is_mem_op  ;
wire        es_mem_we     ;
wire [ 1:0] es_mem_size   ;
wire        es_rf_we      ;
wire [ 4:0] es_rd         ;
wire        es_is_mdr_op  ;
wire        es_is_word_op ;
wire [ 3:0] es_alu_op     ;
// wire        es_src1_is_rs1;
wire        es_src1_is_pc ;
// wire        es_src2_is_rs2;
wire        es_src2_is_imm;
wire [63:0] es_immSext    ;
wire [63:0] es_rf_rdata1  ;
wire [63:0] es_rf_rdata2  ;
wire [63:0] es_pc         ;

wire        jmp_stall;
wire        jmp_taken;
wire [63:0] jmp_target;

`ifdef ysyx_040450_ysyxSoc_DIFF
wire [`ysyx_040450_csr2emu_BUS_WD-1:0] csr2emu_bus;
`endif

assign {es_inst         ,
        es_snpc         ,
        es_inst_jal     ,
        es_inst_jalr    ,
        es_inst_fencei  ,
        es_inst_irq     ,
        es_inst_ecall   ,
        es_inst_ebreak  ,
        `ifdef ysyx_040450_OPT_FIT_YSYX3
        es_inst_0x7b    ,
        `endif
        es_inst_mret    ,
        es_is_csr_op    ,
        es_is_mem_op    ,
        es_mem_we       ,
        es_mem_size     ,
        es_rf_we        ,
        es_rd           ,
        es_is_mdr_op    ,
        es_is_word_op   ,
        es_alu_op       ,
        // es_src1_is_rs1  ,
        es_src1_is_pc   ,
        // es_src2_is_rs2  ,
        es_src2_is_imm  ,
        es_immSext      ,
        es_rf_rdata1    ,
        es_rf_rdata2    ,
        es_pc         
       } = ds_to_es_bus_r;

assign jmp_bus       = {jmp_stall,jmp_taken,jmp_target};

wire [15:0] es_alu_op_d;
ysyx_040450_decoder_4_16 u_dec0(.in(es_alu_op), .out(es_alu_op_d));

wire [63:0] es_alu_src1   ;
wire [63:0] es_alu_src2   ;
wire [63:0] es_result     ;
wire [63:0] es_alu_result ;
wire [63:0] es_mdr_result ;

wire es_mdu_i_valid;
// wire es_mdu_i_ready;
wire es_mdu_o_valid;
// wire es_mdu_o_ready;
assign es_mdu_i_valid = es_valid & es_is_mdr_op;

wire es_res_from_mem;
assign es_res_from_mem = es_is_mem_op & ~es_mem_we;

assign es_to_ms_bus = {es_inst         , // 32
                    //    es_inst_jal     , // 1
                    //    es_inst_jalr    , // 1
                       es_inst_ebreak  ,
                       `ifdef ysyx_040450_OPT_FIT_YSYX3
                       es_inst_0x7b    ,
                       `endif
                       es_res_from_mem , // 1
                    //    es_mem_size     , // 2
                       es_rf_we        ,  //69:69 1
                       es_rd           ,  //68:64 5
                       es_result       ,  //63:32 64
                       es_pc              //31:0  64
                      };

assign es_ready_go    = es_is_mdr_op ? es_mdu_o_valid :
                        es_is_mem_op ? (data_sram_req & data_sram_addr_ok) :
                        es_inst_fencei ? (fencei_req & fencei_ack) :
                        1'b1;//1'b1;
assign es_allowin     = !es_valid || es_ready_go && ms_allowin;
assign es_to_ms_valid =  es_valid && es_ready_go;
always @(posedge clk) begin
    if (!resetn) begin
        es_valid <= 1'b0;
    end
    else if (es_allowin) begin
        es_valid <= ds_to_es_valid;
    end

    if (ds_to_es_valid && es_allowin) begin
        ds_to_es_bus_r <= ds_to_es_bus;
    end
end

assign es_alu_src1 = es_src1_is_pc  ? es_pc :
                                      es_rf_rdata1;
assign es_alu_src2 = es_src2_is_imm ? es_immSext :
                                      es_rf_rdata2;

ysyx_040450_alu u_alu(
    .alu_op    (es_alu_op_d  ),
    .is_word_op(es_is_word_op),
    .in_a      (es_alu_src1  ),
    .in_b      (es_alu_src2  ),
    .result    (es_alu_result)
    );

`ifndef ysyx_040450_FPGA_IMPL
    `ifndef ysyx_040450_OPT_MDU_SIMPLE_IMPL
    // 不实现握手信号，valid输入随时响应，valid输出在没有新的输入时保持
    ysyx_040450_exe_mdu u_exe_mdu(
        .mdu_op_i     (es_alu_op_d   ),
        .is_word_op_i (es_is_word_op ),
        .in_a_i       (es_alu_src1   ),
        .in_b_i       (es_alu_src2   ),
        .result_o     (es_mdr_result ),
        // .mdu_flush_i  (),
        .mdu_i_valid_i(es_mdu_i_valid),
        // .mdu_i_ready_o(),
        .mdu_o_valid_o(es_mdu_o_valid),
        // .mdu_o_ready_i(),

        .clk(clk),
        .rst_n(resetn)
    );
    `else
    ysyx_040450_exe_mdr #(5) u_exe_mdr(
        .alu_op    (es_alu_op_d   ),
        .is_word_op(es_is_word_op ),
        .in_a      (es_alu_src1   ),
        .in_b      (es_alu_src2   ),
        .result    (es_mdr_result ),
        .out_valid (es_mdu_o_valid),
        .clk(clk),
        .rst_n(resetn)
        );
    `endif
`else
assign es_mdr_result = 64'hdeadbeefdeadbeef;
`endif
wire csr_i_valid = es_valid & es_is_csr_op;

wire csr_ena;
wire csr_wr_en;
wire csr_rd_en;
wire [12-1:0] csr_idx;
wire [`ysyx_040450_XLEN-1:0] read_csr_dat;
wire [`ysyx_040450_XLEN-1:0] wbck_csr_dat;
wire [`ysyx_040450_XLEN-1:0] csr_o_wbck_wdat;

wire [`ysyx_040450_XLEN-1:0] cmt_epc;
wire cmt_epc_ena;
wire [`ysyx_040450_XLEN-1:0] cmt_cause;
wire cmt_cause_ena;
wire cmt_instret_ena;
wire [`ysyx_040450_XLEN-1:0]   csr_epc_r  ;
wire [`ysyx_040450_XLEN-1:0]   csr_mtvec_r;
wire cmt_status_ena;
wire cmt_mret_ena;

ysyx_040450_csr_ctrl u_csr_ctrl(
    .csr_i_valid (csr_i_valid  ),
    // .csr_i_ready (),
   
    .rs1_data    (es_rf_rdata1 ),
    .inst        (es_inst      ),
    .csr_i_rdwen (es_rf_we     ),
   
    .csr_ena     (csr_ena     ),
    .csr_wr_en   (csr_wr_en   ),
    .csr_rd_en   (csr_rd_en   ),
    .csr_idx     (csr_idx     ),
    .read_csr_dat(read_csr_dat),
    .wbck_csr_dat(wbck_csr_dat),

    // .csr_o_valid (),
    // .csr_o_ready (),
    .csr_o_wbck_wdat(csr_o_wbck_wdat)
    
    // .clk(clk),
    // .rst_n(resetn)
);

assign cmt_epc       = es_pc;
assign cmt_epc_ena   = (es_inst_ecall|es_inst_irq) & es_valid;
assign cmt_cause[63] = es_inst_irq ? 1'b1 : 1'b0;
assign cmt_cause[62:16] = 47'd0;
assign cmt_cause[15:0]  = es_inst_irq ? ( 16'b0
                                    | ({16{es_alu_op[2]}} & 16'd11)
                                    | ({16{es_alu_op[1]}} & 16'd3)
                                    | ({16{es_alu_op[0]}} & 16'd7)
                        ) : 16'd11; // ecall from M-mode
assign cmt_cause_ena = cmt_epc_ena;
assign cmt_instret_ena = es_to_ms_valid & ms_allowin; // 指令计数
assign cmt_status_ena = cmt_epc_ena; // 异常/中断提交信号
assign cmt_mret_ena  = es_inst_mret & es_valid;
ysyx_040450_csr u_csr_regfile(
    .csr_ena     (csr_ena     ),
    .csr_wr_en   (csr_wr_en   ),
    .csr_rd_en   (csr_rd_en   ),
    .csr_idx     (csr_idx     ),
    .read_csr_dat(read_csr_dat),
    .wbck_csr_dat(wbck_csr_dat),

    .plic_ext_irq (plic_ext_irq ),
    .clint_sft_irq(clint_sft_irq),
    .clint_tmr_irq(clint_tmr_irq),

    .csr_status_MIE_r(csr_status_MIE_r),
    .csr_mie_MEIE_r  (csr_mie_MEIE_r  ),
    .csr_mie_MTIE_r  (csr_mie_MTIE_r  ),
    .csr_mie_MSIE_r  (csr_mie_MSIE_r  ),

    .cmt_epc        (cmt_epc        ),
    .cmt_epc_ena    (cmt_epc_ena    ),
    .cmt_cause      (cmt_cause      ),
    .cmt_cause_ena  (cmt_cause_ena  ),
    .cmt_instret_ena(cmt_instret_ena),

    .csr_epc_r    (csr_epc_r    ),
    .csr_mtvec_r  (csr_mtvec_r  ),

    .cmt_status_ena(cmt_status_ena),
    .cmt_mret_ena  (cmt_mret_ena  ),

    `ifdef ysyx_040450_ysyxSoc_DIFF
    .csr2emu_bus(csr2emu_bus),
    `endif
    
    .clk(clk),
    .rst_n(resetn)
);
assign es_inst_env = (es_inst_ecall | es_inst_ebreak | es_inst_irq) & es_valid;

assign es_result  = (es_inst_jal | es_inst_jalr) ? es_snpc :
                    es_is_mdr_op ? es_mdr_result :
                    es_is_csr_op ? csr_o_wbck_wdat :
                                  es_alu_result;
assign jmp_leaving = jmp_taken && ms_allowin;
assign jmp_stall = ( /*es_inst_mret|es_inst_ecall|es_inst_irq|*/es_inst_fencei
                    ) && es_valid; // csr stall
assign jmp_taken = (es_inst_mret|es_inst_ecall|es_inst_irq) & es_valid;//(es_inst_jal | es_inst_jalr) & es_valid;
assign jmp_target = es_inst_mret ? csr_epc_r :
                    csr_mtvec_r;//es_alu_result;

// forward
assign es_fwd_o =  {(es_res_from_mem||es_is_mdr_op)&es_valid ,
                    es_rf_we&es_valid        ,  //69:69 1
                    es_rd           ,  //68:64 5
                    es_result       
                   };

// mem act
wire [7:0] store_byte_en;
wire addr000 = es_alu_result[2:0]==3'b000;
wire addr001 = es_alu_result[2:0]==3'b001;
wire addr010 = es_alu_result[2:0]==3'b010;
wire addr011 = es_alu_result[2:0]==3'b011;
wire addr100 = es_alu_result[2:0]==3'b100;
wire addr101 = es_alu_result[2:0]==3'b101;
wire addr110 = es_alu_result[2:0]==3'b110;
wire addr111 = es_alu_result[2:0]==3'b111;
wire size00 = es_mem_size==2'b00;
wire size01 = es_mem_size==2'b01;
wire size10 = es_mem_size==2'b10;
wire size11 = es_mem_size==2'b11;
assign store_byte_en[0] = addr000&size00 || addr000&size01 || addr000&size10 || addr000&size11;
assign store_byte_en[1] = addr001&size00 || addr000&size01 || addr000&size10 || addr000&size11;
assign store_byte_en[2] = addr010&size00 || addr010&size01 || addr000&size10 || addr000&size11;
assign store_byte_en[3] = addr011&size00 || addr010&size01 || addr000&size10 || addr000&size11;
assign store_byte_en[4] = addr100&size00 || addr100&size01 || addr100&size10 || addr000&size11;
assign store_byte_en[5] = addr101&size00 || addr100&size01 || addr100&size10 || addr000&size11;
assign store_byte_en[6] = addr110&size00 || addr110&size01 || addr100&size10 || addr000&size11;
assign store_byte_en[7] = addr111&size00 || addr110&size01 || addr100&size10 || addr000&size11;

assign data_sram_req   = (es_is_mem_op) && es_valid && ms_allowin;
assign data_sram_wr    = es_mem_we & es_valid;
assign data_sram_size  = es_mem_size;
assign data_sram_wstrb = store_byte_en;
assign data_sram_addr  = es_alu_result;

assign fencei_req = (es_inst_fencei) && es_valid && ms_allowin;
// assign data_sram_wdata = es_rf_rdata2;
ysyx_040450_MuxKey #(4, 2, 64) i_MuxKey_store_data_sel (data_sram_wdata, es_mem_size, {
    2'b00, {8{es_rf_rdata2[7:0]}},
    2'b01, {4{es_rf_rdata2[15:0]}},
    2'b10, {2{es_rf_rdata2[31:0]}},
    2'b11, es_rf_rdata2
});

`ifdef ysyx_040450_ZEMU_DIFF
import "DPI-C" function void rtl2emu_exe(input bit valid, input longint next_pc, input int next_inst,input bit is_mmio_op);
wire zemu_is_mmio_req = (
       data_sram_addr[31:24]==8'h02 // clint
    || data_sram_addr[31:28]==4'ha // zemu device
    ) && data_sram_req;
always @(*) begin
        rtl2emu_exe(es_to_ms_valid&&ms_allowin, es_pc, es_inst, zemu_is_mmio_req|es_is_csr_op|es_inst_mret|es_inst_env);
end
`endif

`ifdef ysyx_040450_ysyxSoc_DIFF
// skip - load from clint
wire zemu_is_mmio_req = (
       data_sram_addr[31:24]==8'h02 // clint
    ) && data_sram_req;
wire diff_es_cmtskip = zemu_is_mmio_req;

assign diff_es_bus = {diff_es_cmtskip,csr2emu_bus};
`endif

`ifdef ysyx_040450_DBG_early_stop_fencei
reg cnnnnt_on;
reg [15:0] cnnnnt;
always @(posedge clk)begin
    if(!resetn) cnnnnt_on <= 1'd0;
    else if(es_inst_fencei) cnnnnt_on <= 1'd1;
end
always @(posedge clk)begin
    if(!resetn) cnnnnt <= 16'd0;
    else if(cnnnnt_on) cnnnnt <= cnnnnt + 1'b1;
    else cnnnnt <= cnnnnt;
end
always @(posedge clk)begin
    if(cnnnnt>16'd4096)$finish;
end
`endif
`ifdef ysyx_040450_DBG_dead_det
reg [31:0] DBG_last_inst;
reg [15:0] DBG_dead_cnt;
always @(posedge clk)begin
    if(!resetn) DBG_last_inst <= 32'd0;
    else DBG_last_inst <= es_inst;
end
always @(posedge clk)begin
    if(!resetn) DBG_last_inst <= 32'd0;
    else if(es_inst_fencei) DBG_last_inst <= es_inst;
end
always @(posedge clk)begin
    if(DBG_dead_cnt>16'd4096)begin
        $finish;
    end
end
`endif

endmodule

module ysyx_040450_mem_stage(
    //allowin
    input                          ws_allowin    ,
    output                         ms_allowin    ,
    //from es
    input                          es_to_ms_valid,
    input  [`ysyx_040450_ES_TO_MS_BUS_WD -1:0] es_to_ms_bus  ,
    //to ws
    output                         ms_to_ws_valid,
    output [`ysyx_040450_MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus  ,
    // forward to ds
    output [`ysyx_040450_MS_FWD_BUS_WD   -1:0] ms_fwd_o      ,
    // //to fs
    // output [`ysyx_040450_JMP_BUS_WD       -1:0] jmp_bus      ,
    //from data-sram
    input                          data_sram_data_ok,
    input  [63                 :0] data_sram_rdata  ,
    // diff
    `ifdef ysyx_040450_ysyxSoc_DIFF
    input  [`ysyx_040450_diff_es_BUS_WD-1:0] diff_es_bus,
    output [`ysyx_040450_diff_ms_BUS_WD-1:0] diff_ms_bus,
    `endif
    input                          clk           ,
    input                          resetn        
);

reg         ms_valid;
wire        ms_ready_go;

reg [`ysyx_040450_ES_TO_MS_BUS_WD -1:0] es_to_ms_bus_r;
wire [31:0] ms_inst         ;
// wire        ms_inst_jal     ;
// wire        ms_inst_jalr    ;
wire        ms_inst_ebreak  ;
`ifdef ysyx_040450_OPT_FIT_YSYX3
wire        ms_inst_0x7b    ;
`endif
wire        ms_res_from_mem ;
// wire [ 1:0] ms_mem_size     ;
wire        ms_rf_we        ;
wire [ 4:0] ms_rd           ;
wire [63:0] ms_exe_result   ;
wire [63:0] ms_pc           ;

// wire        jmp_taken;
// wire [63:0] jmp_target;

assign {ms_inst        ,
        // ms_inst_jal    ,
        // ms_inst_jalr   ,
        ms_inst_ebreak ,
        `ifdef ysyx_040450_OPT_FIT_YSYX3
        ms_inst_0x7b   ,
        `endif
        ms_res_from_mem,  //70:70
        // ms_mem_size    , // unused 且可以直接从ms_inst取
        ms_rf_we       ,
        ms_rd          ,
        ms_exe_result  ,   //127:64
        ms_pc              // 63:0
       } = es_to_ms_bus_r;

wire [63:0] mem_result;
wire [63:0] ms_final_result;

// assign jmp_bus       = {jmp_taken,jmp_target};

assign ms_to_ws_bus  = {ms_inst        ,  // 32
                        ms_inst_ebreak ,
                        `ifdef ysyx_040450_OPT_FIT_YSYX3
                        ms_inst_0x7b   ,
                        `endif
                        ms_rf_we       ,  //69:69 1
                        ms_rd          ,  //68:64 5
                        ms_final_result,  //63:32 64
                        ms_pc             //31:0  64
                       };

assign ms_ready_go    = ms_res_from_mem ? (data_sram_data_ok) :
                                            1'b1;
assign ms_allowin     = !ms_valid || ms_ready_go && ws_allowin;
assign ms_to_ws_valid = ms_valid && ms_ready_go;
always @(posedge clk) begin
    if (!resetn) begin
        ms_valid <= 1'b0;
    end
    else if (ms_allowin) begin
        ms_valid <= es_to_ms_valid;
    end

    if (es_to_ms_valid && ms_allowin) begin
        es_to_ms_bus_r <= es_to_ms_bus;
    end
end

// forward
assign ms_fwd_o = {ms_res_from_mem&ms_valid,
                   ms_rf_we&ms_valid        ,  //69:69 1
                   ms_rd           ,  //68:64 5
                   ms_final_result       
                  };

// mem act
// assign mem_result = data_sram_rdata;
wire [7:0] load_byte;
wire [15:0] load_halfword;
wire [31:0] load_word;
`ifdef ysyx_040450_UNALIGNED_MEM
assign load_byte     = data_sram_rdata[ 7:0];
assign load_halfword = data_sram_rdata[15:0];
assign load_word     = data_sram_rdata[31:0];
`else
ysyx_040450_MuxKey #(8, 3, 8) i_load_byte_sel (load_byte, ms_exe_result[2:0], {
    3'b000, data_sram_rdata[7:0],
    3'b001, data_sram_rdata[15:8],
    3'b010, data_sram_rdata[23:16],
    3'b011, data_sram_rdata[31:24],
    3'b100, data_sram_rdata[39:32],
    3'b101, data_sram_rdata[47:40],
    3'b110, data_sram_rdata[55:48],
    3'b111, data_sram_rdata[63:56]
});
ysyx_040450_MuxKey #(4, 2, 16) i_load_halfword_sel (load_halfword, ms_exe_result[2:1], {
    2'b00, data_sram_rdata[15:0],
    2'b01, data_sram_rdata[31:16],
    2'b10, data_sram_rdata[47:32],
    2'b11, data_sram_rdata[63:48]
});
ysyx_040450_MuxKey #(2, 1, 32) i_load_word_sel (load_word, ms_exe_result[2], {
    1'b0, data_sram_rdata[31:0],
    1'b1, data_sram_rdata[63:32]
});
`endif

ysyx_040450_MuxKey #(7, 3, 64) i_load_data_sel (mem_result, ms_inst[14:12], {
    3'b000, {{56{load_byte[7]}}, load_byte},
    3'b001, {{48{load_halfword[15]}}, load_halfword},
    3'b010, {{32{load_word[31]}}, load_word},
    3'b011, data_sram_rdata,
    3'b100, {{56{1'b0}}, load_byte},
    3'b101, {{48{1'b0}}, load_halfword},
    3'b110, {{32{1'b0}}, load_word}
});

assign ms_final_result = ms_res_from_mem ? mem_result
                                         : ms_exe_result;

// `ifndef ysyx_040450_ZEMU_DIFF
// import "DPI-C" function void rtl2emu_exe(input bit valid, input longint next_pc, input int next_inst);
// always @(*) begin
//         rtl2emu_exe(ms_to_ws_valid&&ws_allowin, ms_pc, ms_inst);
// end
// `endif

// always @ (posedge clk) begin
//     AssertionFalse1: assert (resetn || !resetn) 
//     else $error( "SVA ERROR: both write ports write to the index=" );
// end
// cover property (@(posedge clk) mem_result==0);

`ifdef ysyx_040450_ysyxSoc_DIFF
reg [`ysyx_040450_diff_es_BUS_WD-1:0] diff_es_bus_r;
always @(posedge clk) begin
    if (es_to_ms_valid && ms_allowin) begin
        diff_es_bus_r <= diff_es_bus;
    end
end
assign diff_ms_bus = diff_es_bus_r;
`endif

endmodule    

module ysyx_040450_wb_stage(
    //allowin
    output                          ws_allowin    ,
    //from ms
    input                           ms_to_ws_valid,
    input  [`ysyx_040450_MS_TO_WS_BUS_WD -1:0]  ms_to_ws_bus  ,
    //to rf: for write back
    output [`ysyx_040450_WS_TO_RF_BUS_WD -1:0]  ws_to_rf_bus  ,
    output ebreak,
    `ifdef ysyx_040450_ysyxSoc_DIFF
    `ifdef ysyx_040450_OPT_FIT_YSYX3
    output inst_0x7b,
    `endif
    input [`ysyx_040450_diff_ms_BUS_WD-1:0] diff_ms_bus,
    output [`ysyx_040450_csr2emu_BUS_WD-1:0] csr2emu_bus,
    output [31:0] diff_intrNO     ,
    output [63:0] diff_exceptionPC,
    output        cmt_valid,
    output [63:0] cmt_pc   ,
    output [31:0] cmt_inst ,
    output        cmt_skip ,
    output        cmt_wen  ,
    output [ 7:0] cmt_wdest,
    output [63:0] cmt_wdata,
    `endif
    `ifdef ysyx_040450_ZEMU_DIFF
    //trace debug interface
    output [`ysyx_040450_DBG_WB_BUS_WD   -1:0]  debug_wb_bus  ,
    `endif
    input                           clk           ,
    input                           resetn        
);

reg         ws_valid;
wire        ws_ready_go;

reg [`ysyx_040450_MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus_r;
wire [31:0] ws_inst;
wire        ws_rf_we;
wire [ 4:0] ws_dest;
wire [63:0] ws_final_result;
wire [63:0] ws_pc;
assign {ws_inst        ,
        ebreak         ,
        `ifdef ysyx_040450_OPT_FIT_YSYX3
        inst_0x7b      ,
        `endif
        ws_rf_we       ,  //69:69
        ws_dest        ,  //68:64
        ws_final_result,  //63:32
        ws_pc             //31:0
       } = ms_to_ws_bus_r;

wire        rf_we;
wire [4 :0] rf_waddr;
wire [63:0] rf_wdata;
assign ws_to_rf_bus = {rf_we   ,  //37:37 1
                       rf_waddr,  //36:32 5
                       rf_wdata   //31:0  64
                      };

assign ws_ready_go = 1'b1;
assign ws_allowin  = !ws_valid || ws_ready_go;
always @(posedge clk) begin
    if (!resetn) begin
        ws_valid <= 1'b0;
    end
    else if (ws_allowin) begin
        ws_valid <= ms_to_ws_valid;
    end

    if (ms_to_ws_valid && ws_allowin) begin
        ms_to_ws_bus_r <= ms_to_ws_bus;
    end
end

assign rf_we    = ws_rf_we&&ws_valid;
assign rf_waddr = ws_dest;
assign rf_wdata = ws_final_result;

`ifdef ysyx_040450_ZEMU_DIFF
// debug info generate
wire [63:0] debug_wb_pc      ;
wire [63:0] debug_wb_dnpc    ;
wire [ 7:0] debug_wb_rf_wen  ;
wire [ 4:0] debug_wb_rf_wnum ;
wire [63:0] debug_wb_rf_wdata;
assign debug_wb_pc       = ws_pc;
assign debug_wb_dnpc     = ws_pc;
assign debug_wb_rf_wen   = {8{rf_we}};
assign debug_wb_rf_wnum  = ws_dest;
assign debug_wb_rf_wdata = ws_final_result;
assign debug_wb_bus = {ws_valid     ,
                       ws_inst      ,
                       debug_wb_pc  ,
                       debug_wb_dnpc
                      };

import "DPI-C" function void rtl2emu_commit(input bit valid, input longint next_pc, input int next_inst);
always @(*) begin
        rtl2emu_commit(ws_valid&&ws_ready_go, ws_pc, ws_inst);
end

import "DPI-C" function void ebreak_request(input longint pc);
always @(*) begin
  if (resetn && ebreak) ebreak_request(debug_wb_pc);
end
`endif

`ifdef ysyx_040450_ysyxSoc_DIFF
reg [`ysyx_040450_diff_ms_BUS_WD-1:0] diff_ms_bus_r;
wire diff_es_cmtskip;
always @(posedge clk) begin
    if (ms_to_ws_valid && ws_allowin) begin
        diff_ms_bus_r <= diff_ms_bus;
    end
end
assign {diff_es_cmtskip,csr2emu_bus} = diff_ms_bus_r;
`endif

`ifdef ysyx_040450_ysyxSoc_DIFF
wire [ 6:0] diff_opcode = ws_inst[6:0];
wire [ 3:0] diff_funct3 = ws_inst[14:12];
wire [12:0] diff_csrid  = ws_inst[31:20];

wire diff_inst_0x7b = ws_inst=={57'h0,7'h7b};
wire diff_inst_0x7f = ws_inst=={57'h0,7'h7f}; // timer intr
wire diff_inst_csr_mcycle = diff_csrid==12'hb00 
                         && !(diff_funct3==3'h00)
                         && diff_opcode==7'h73;
// ecall 不需要 skip
// wire diff_inst_ecall = diff_funct3==3'h00
//                     && diff_opcode==7'h73; 
assign diff_intrNO      = (ws_valid&&ws_ready_go && diff_inst_0x7f) ? 32'd7 : 32'd0;
assign diff_exceptionPC = diff_intrNO > 0 ? ws_pc : 64'h0;
assign cmt_valid = ws_valid&&ws_ready_go && !diff_inst_0x7f;
assign cmt_pc    = ws_pc;
assign cmt_inst  = ws_inst;
assign cmt_skip  = diff_inst_0x7b | diff_inst_csr_mcycle | diff_es_cmtskip;
assign cmt_wen   = rf_we;
assign cmt_wdest = {3'd0, rf_waddr};
assign cmt_wdata = rf_wdata;
`endif
endmodule
module ysyx_040450_exception(
    // from irq src
    input         plic_ext_irq , // 优先级递减
    input         clint_sft_irq,
    input         clint_tmr_irq,
    // from pipeline/csr - enable signal
    input         csr_status_MIE_r,
    input         csr_mie_MEIE_r  ,
    input         csr_mie_MTIE_r  ,
    input         csr_mie_MSIE_r  ,
    input         es_inst_env     ,
    // 
    output        excp_irq_valid,
    input         excp_irq_ready,
    output [2:0]  excp_irq_type ,

    input clk,
    input resetn
);

wire irq_valid;
wire ext_irq_valid;
wire sft_irq_valid;
wire tmr_irq_valid;
reg [2:0] irq_type_r;

wire global_exception_ready = !es_inst_env & csr_status_MIE_r;

parameter IDLE = 3'b001;
parameter REQ  = 3'b010;
parameter DONE = 3'b100;
reg [2:0] m_state_c;
reg [2:0] m_state_n;

always @(posedge clk)begin 
    if(!resetn) m_state_c <= IDLE;
    else m_state_c <= m_state_n;
end 

always @(*)begin 
    case(m_state_c)
        IDLE:begin 
            if(irq_valid & excp_irq_ready)begin 
                m_state_n = DONE;
            end
            else if(irq_valid & !excp_irq_ready)begin
                m_state_n = REQ;
            end
            else begin
                m_state_n = IDLE;
            end 
        end
        REQ:begin 
            if(excp_irq_ready)begin
                m_state_n = DONE;
            end
            else begin
                m_state_n = REQ;
            end 
        end 
        DONE:begin 
            m_state_n = IDLE;
        end 
        default: m_state_n = IDLE;
    endcase
end 

assign excp_irq_valid = m_state_c==IDLE ? irq_valid :
                        m_state_c==REQ  ? 1'b1 :
                        /*m_state_c==DONE*/ 1'b0;

always @(posedge clk) begin
    if(!resetn)
        irq_type_r <= 3'b000;
    else if(irq_valid)
        irq_type_r <= {ext_irq_valid,sft_irq_valid,tmr_irq_valid};
    else
        irq_type_r <= irq_type_r;
end

assign excp_irq_type = m_state_c==IDLE ? {ext_irq_valid,sft_irq_valid,tmr_irq_valid} :
                       m_state_c==REQ  ? irq_type_r :
                       /*m_state_c==DONE*/ 3'b000;

assign irq_valid = (ext_irq_valid | sft_irq_valid | tmr_irq_valid) & global_exception_ready;
// assign ext_irq_valid =  plic_ext_irq & global_exception_ready;
// assign sft_irq_valid =  !plic_ext_irq & clint_sft_irq & global_exception_ready;
// assign tmr_irq_valid =  !plic_ext_irq & !clint_sft_irq & clint_tmr_irq & global_exception_ready;
// FIXME 0921 补全中断使能逻辑，未测试
assign ext_irq_valid =  plic_ext_irq & csr_mie_MEIE_r;
assign sft_irq_valid =  !ext_irq_valid & clint_sft_irq & csr_mie_MTIE_r;
assign tmr_irq_valid =  !ext_irq_valid & !sft_irq_valid & clint_tmr_irq & csr_mie_MSIE_r;

endmodule
/*
* ysyx_040450_cpu_biu bus interface unit
*/
module ysyx_040450_cpu_biu(
    // core data bus - input
    input         data_sram_req    ,
    input         data_sram_wr     ,
    input  [1 :0] data_sram_size   ,
    input  [7 :0] data_sram_wstrb  ,
    input  [63:0] data_sram_addr   ,
    input  [63:0] data_sram_wdata  ,
    output        data_sram_addr_ok,
    output        data_sram_data_ok,
    output [63:0] data_sram_rdata  ,

    // cpu data bus - output
    output        cpu_data_req    ,
    output        cpu_data_wr     ,
    output [1 :0] cpu_data_size   ,
    output [7 :0] cpu_data_wstrb  ,
    output [63:0] cpu_data_addr   ,
    output [63:0] cpu_data_wdata  ,
    input         cpu_data_addr_ok,
    input         cpu_data_data_ok,
    input  [63:0] cpu_data_rdata  ,

    // clint bus - output
    output        clint_data_req    ,
    output        clint_data_wr     ,
    output [1 :0] clint_data_size   ,
    output [7 :0] clint_data_wstrb  ,
    output [63:0] clint_data_addr   ,
    output [63:0] clint_data_wdata  ,
    input         clint_data_addr_ok,
    input         clint_data_data_ok,
    input  [63:0] clint_data_rdata  ,

    input clk,
    input rst_n
);
wire [63:0] req_addr_hold;
wire is_out_of_core_req;
wire is_clint_req;

reg  req_buffer_valid;
reg [63:0] data_sram_addr_r;

assign req_addr_hold = req_buffer_valid ? data_sram_addr_r : data_sram_addr;
// 所有非核内设备的请求都发送到外部总线，避免访问未分配区段时，\
// 流水线收不到握手信号持续等待
// FIXME cache 模块目前可能有类似问题
assign is_out_of_core_req = ~is_clint_req;
assign is_clint_req = (req_addr_hold[31:24]==8'h02);


///////////////////////////////////////
always @(posedge clk)begin 
    if(!rst_n) begin
        req_buffer_valid <=  1'b0;
    end
    else if(req_buffer_valid==1'b0 && data_sram_req==1'b1)begin
        req_buffer_valid <= 1'b1;
    end
    else if(req_buffer_valid==1'b1 && (is_out_of_core_req&&cpu_data_data_ok||is_clint_req&&clint_data_data_ok) && data_sram_req==1'b1)begin
        req_buffer_valid <= 1'b1;
    end
    else if(req_buffer_valid==1'b1 && (is_out_of_core_req&&cpu_data_data_ok||is_clint_req&&clint_data_data_ok) && data_sram_req==1'b0)begin
        req_buffer_valid <= 1'b0;
    end
    else begin
        req_buffer_valid <= req_buffer_valid;
    end
end 
always @(posedge clk)begin 
    if(!rst_n) begin
        data_sram_addr_r <= 64'b0;
    end
    else if(req_buffer_valid==1'b0 && data_sram_req==1'b1)begin
        data_sram_addr_r <= data_sram_addr;
    end
    else if(req_buffer_valid==1'b1 && data_sram_req==1'b1 && (is_out_of_core_req&&cpu_data_data_ok||is_clint_req&&clint_data_data_ok))begin
        data_sram_addr_r <= data_sram_addr;
    end
    else begin
        data_sram_addr_r <= data_sram_addr_r;
    end
end 

///////////////////////////////////////
assign cpu_data_req     = is_out_of_core_req ? data_sram_req     :  1'b0;
assign cpu_data_wr      = is_out_of_core_req ? data_sram_wr      :  1'b0;
assign cpu_data_size    = is_out_of_core_req ? data_sram_size    :  2'd0;
assign cpu_data_wstrb   = is_out_of_core_req ? data_sram_wstrb   :  8'd0;
assign cpu_data_addr    = is_out_of_core_req ? data_sram_addr    : 64'd0;
assign cpu_data_wdata   = is_out_of_core_req ? data_sram_wdata   : 64'd0;

assign clint_data_req     = is_clint_req ? data_sram_req     :  1'b0;
assign clint_data_wr      = is_clint_req ? data_sram_wr      :  1'b0;
assign clint_data_size    = is_clint_req ? data_sram_size    :  2'd0;
assign clint_data_wstrb   = is_clint_req ? data_sram_wstrb   :  8'd0;
assign clint_data_addr    = is_clint_req ? data_sram_addr    : 64'd0;
assign clint_data_wdata   = is_clint_req ? data_sram_wdata   : 64'd0;

assign data_sram_addr_ok  = is_clint_req ? clint_data_addr_ok :
                            is_out_of_core_req ? cpu_data_addr_ok :
                            1'b0;
assign data_sram_data_ok  = is_clint_req ? clint_data_data_ok :
                            is_out_of_core_req ? cpu_data_data_ok :
                            1'b0;
assign data_sram_rdata    = is_clint_req ? clint_data_rdata :
                            is_out_of_core_req ? cpu_data_rdata :
                            64'd0;
endmodule

module ysyx_040450_core(
    input         clk,
    input         resetn,
    // inst sram interface
    output        inst_sram_req    ,
    output        inst_sram_wr     ,
    output [1 :0] inst_sram_size   ,
    output [7 :0] inst_sram_wstrb  ,
    output [63:0] inst_sram_addr   ,
    output [63:0] inst_sram_wdata  ,
    input         inst_sram_addr_ok,
    input         inst_sram_data_ok,
    input  [63:0] inst_sram_rdata  ,
    // data sram interface
    output        data_sram_req    ,
    output        data_sram_wr     ,
    output [1 :0] data_sram_size   ,
    output [7 :0] data_sram_wstrb  ,
    output [63:0] data_sram_addr   ,
    output [63:0] data_sram_wdata  ,
    input         data_sram_addr_ok,
    input         data_sram_data_ok,
    input  [63:0] data_sram_rdata  ,
    
    input         plic_ext_irq , // 优先级递减
    input         clint_sft_irq,
    input         clint_tmr_irq,

    `ifdef ysyx_040450_ZEMU_DIFF
    //trace debug interface
    output [`ysyx_040450_DBG_WB_BUS_WD   -1:0]  debug_wb_bus  ,
    `endif
    
    output fencei_req,
    input  fencei_ack
);

wire         ds_allowin;
wire         es_allowin;
wire         ms_allowin;
wire         ws_allowin;
wire         fs_to_ds_valid;
wire         ds_to_es_valid;
wire         es_to_ms_valid;
wire         ms_to_ws_valid;
wire [`ysyx_040450_FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus;
wire [`ysyx_040450_DS_TO_ES_BUS_WD -1:0] ds_to_es_bus;
wire [`ysyx_040450_ES_TO_MS_BUS_WD -1:0] es_to_ms_bus;
wire [`ysyx_040450_MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus;
wire [`ysyx_040450_WS_TO_RF_BUS_WD -1:0] ws_to_rf_bus;
wire [`ysyx_040450_BR_BUS_WD       -1:0] br_bus; // br branch
wire          br_leaving;
wire [`ysyx_040450_JMP_BUS_WD      -1:0] jmp_bus; // jal jalr
wire          jmp_leaving;

wire [`ysyx_040450_ES_FWD_BUS_WD   -1:0] es_fwd_bus;
wire [`ysyx_040450_MS_FWD_BUS_WD   -1:0] ms_fwd_bus;

wire excp_irq_valid;
wire excp_irq_ready;
wire [2:0] excp_irq_type;
wire csr_status_MIE_r;
wire csr_mie_MEIE_r  ;
wire csr_mie_MTIE_r  ;
wire csr_mie_MSIE_r  ;
wire es_inst_env;


wire ebreak;
`ifdef ysyx_040450_ysyxSoc_DIFF
wire inst_0x7b;
wire [`ysyx_040450_diff_es_BUS_WD-1:0] diff_es_bus;
wire [`ysyx_040450_diff_ms_BUS_WD-1:0] diff_ms_bus;
wire [`ysyx_040450_csr2emu_BUS_WD-1:0] csr2emu_bus;
wire [31:0] diff_intrNO     ;
wire [63:0] diff_exceptionPC;
wire        cmt_valid;
wire [63:0] cmt_pc   ;
wire [31:0] cmt_inst ;
wire        cmt_skip ;
wire        cmt_wen  ;
wire [ 7:0] cmt_wdest;
wire [63:0] cmt_wdata;
wire [63:0] rf_regs [0:31];
`endif

// IF stage
ysyx_040450_if_stage if_stage(
    //allowin
    .ds_allowin     (ds_allowin     ),
    //brbus
    .br_bus         (br_bus         ),
    .br_leaving     (br_leaving     ),
    //jmpbus
    .jmp_bus        (jmp_bus        ),
    .jmp_leaving    (jmp_leaving    ),
    //outputs
    .fs_to_ds_valid (fs_to_ds_valid ),
    .fs_to_ds_bus   (fs_to_ds_bus   ),
    // inst sram interface
    .inst_sram_req    (inst_sram_req    ),
    .inst_sram_wr     (inst_sram_wr     ),
    .inst_sram_size   (inst_sram_size   ),
    .inst_sram_wstrb  (inst_sram_wstrb  ),
    .inst_sram_addr   (inst_sram_addr   ),
    .inst_sram_wdata  (inst_sram_wdata  ),
    .inst_sram_addr_ok(inst_sram_addr_ok),
    .inst_sram_data_ok(inst_sram_data_ok),
    .inst_sram_rdata  (inst_sram_rdata  ),
    .clk            (clk            ),
    .resetn         (resetn         )
);
// ID stage
ysyx_040450_id_stage id_stage(
    //allowin
    .es_allowin     (es_allowin     ),
    .ds_allowin     (ds_allowin     ),
    //from fs
    .fs_to_ds_valid (fs_to_ds_valid ),
    .fs_to_ds_bus   (fs_to_ds_bus   ),
    //to es
    .ds_to_es_valid (ds_to_es_valid ),
    .ds_to_es_bus   (ds_to_es_bus   ),
    //to fs
    .br_bus         (br_bus         ),
    .br_leaving     (br_leaving     ),
    //to rf: for write back
    .ws_to_rf_bus   (ws_to_rf_bus   ),
    //forward from es
    .es_to_ds_fwd_i (es_fwd_bus     ),
    //forward from ms
    .ms_to_ds_fwd_i (ms_fwd_bus     ),
    // irq
    .excp_irq_valid (excp_irq_valid ),
    .excp_irq_ready (excp_irq_ready ),
    .excp_irq_type  (excp_irq_type  ),
    `ifdef ysyx_040450_ysyxSoc_DIFF
    .rf_regs(rf_regs),
    `endif
    .clk            (clk            ),
    .resetn         (resetn         )
);
// EXE stage
ysyx_040450_exe_stage exe_stage(
    //allowin
    .ms_allowin     (ms_allowin     ),
    .es_allowin     (es_allowin     ),
    //from ds
    .ds_to_es_valid (ds_to_es_valid ),
    .ds_to_es_bus   (ds_to_es_bus   ),
    //to ms
    .es_to_ms_valid (es_to_ms_valid ),
    .es_to_ms_bus   (es_to_ms_bus   ),
    //to fs
    .jmp_bus        (jmp_bus        ),
    .jmp_leaving    (jmp_leaving    ),
    //forward to ds
    .es_fwd_o       (es_fwd_bus     ),
    // with csr
    .plic_ext_irq   (plic_ext_irq   ),
    .clint_sft_irq  (clint_sft_irq  ),
    .clint_tmr_irq  (clint_tmr_irq  ),
    // exceptionU
    .csr_status_MIE_r(csr_status_MIE_r),
    .csr_mie_MEIE_r  (csr_mie_MEIE_r  ),
    .csr_mie_MTIE_r  (csr_mie_MTIE_r  ),
    .csr_mie_MSIE_r  (csr_mie_MSIE_r  ),
    .es_inst_env     (es_inst_env     ),
    // cache sync
    .fencei_req(fencei_req),
    .fencei_ack(fencei_ack),
    // data sram interface
    .data_sram_req    (data_sram_req    ),
    .data_sram_wr     (data_sram_wr     ),
    .data_sram_size   (data_sram_size   ),
    .data_sram_wstrb  (data_sram_wstrb  ),
    .data_sram_addr   (data_sram_addr   ),
    .data_sram_wdata  (data_sram_wdata  ),
    .data_sram_addr_ok(data_sram_addr_ok),
    `ifdef ysyx_040450_ysyxSoc_DIFF
    .diff_es_bus(diff_es_bus),
    `endif
    .clk            (clk            ),
    .resetn         (resetn         )
);
// MEM stage
ysyx_040450_mem_stage mem_stage(
    //allowin
    .ws_allowin     (ws_allowin     ),
    .ms_allowin     (ms_allowin     ),
    //from es
    .es_to_ms_valid (es_to_ms_valid ),
    .es_to_ms_bus   (es_to_ms_bus   ),
    //to ws
    .ms_to_ws_valid (ms_to_ws_valid ),
    .ms_to_ws_bus   (ms_to_ws_bus   ),
    //forward to ds
    .ms_fwd_o       (ms_fwd_bus     ),
    //from data-sram
    .data_sram_data_ok(data_sram_data_ok),
    .data_sram_rdata(data_sram_rdata),
    `ifdef ysyx_040450_ysyxSoc_DIFF
    .diff_es_bus(diff_es_bus),
    .diff_ms_bus(diff_ms_bus),
    `endif
    .clk            (clk            ),
    .resetn         (resetn         )
);
// WB stage
ysyx_040450_wb_stage wb_stage(
    //allowin
    .ws_allowin     (ws_allowin     ),
    //from ms
    .ms_to_ws_valid (ms_to_ws_valid ),
    .ms_to_ws_bus   (ms_to_ws_bus   ),
    //to rf: for write back
    .ws_to_rf_bus   (ws_to_rf_bus   ),
    //trace debug interface
    .ebreak         (ebreak         ),
    `ifdef ysyx_040450_ysyxSoc_DIFF
    `ifdef ysyx_040450_OPT_FIT_YSYX3
    .inst_0x7b      (inst_0x7b      ),
    `endif
    .diff_ms_bus(diff_ms_bus),
    .csr2emu_bus(csr2emu_bus),
    .diff_intrNO     (diff_intrNO     ),
    .diff_exceptionPC(diff_exceptionPC),
    .cmt_valid(cmt_valid),
    .cmt_pc   (cmt_pc   ),
    .cmt_inst (cmt_inst ),
    .cmt_skip (cmt_skip ),
    .cmt_wen  (cmt_wen  ),
    .cmt_wdest(cmt_wdest),
    .cmt_wdata(cmt_wdata),
    `endif
    `ifdef ysyx_040450_ZEMU_DIFF
    .debug_wb_bus(debug_wb_bus),
    `endif
    .clk            (clk            ),
    .resetn         (resetn         )
);

ysyx_040450_exception exception_unit(
    .plic_ext_irq (plic_ext_irq ),
    .clint_sft_irq(clint_sft_irq),
    .clint_tmr_irq(clint_tmr_irq),
    .csr_status_MIE_r(csr_status_MIE_r),
    .csr_mie_MEIE_r  (csr_mie_MEIE_r  ),
    .csr_mie_MTIE_r  (csr_mie_MTIE_r  ),
    .csr_mie_MSIE_r  (csr_mie_MSIE_r  ),
    .es_inst_env     (es_inst_env     ),
    .excp_irq_valid(excp_irq_valid),
    .excp_irq_ready(excp_irq_ready),
    .excp_irq_type (excp_irq_type ),
    .clk            (clk            ),
    .resetn         (resetn         )
);

`ifdef ysyx_040450_ysyxSoc_DIFF
reg [31:0] diff_intrNO_r      ;
reg [63:0] diff_exceptionPC_r   ;
reg        cmt_valid_r;
reg [63:0] cmt_pc_r   ;
reg [31:0] cmt_inst_r ;
reg        cmt_skip_r ;
reg        cmt_wen_r  ;
reg [ 7:0] cmt_wdest_r;
reg [63:0] cmt_wdata_r;

reg [63:0] regs_diff [0 : 31];

wire [`ysyx_040450_XLEN-1:0] csr2emu_mcycle  ;
wire [`ysyx_040450_XLEN-1:0] csr2emu_minstret;
wire [`ysyx_040450_XLEN-1:0] csr2emu_mstatus ;
wire [`ysyx_040450_XLEN-1:0] csr2emu_mepc    ;
wire [`ysyx_040450_XLEN-1:0] csr2emu_mtvec   ;
wire [`ysyx_040450_XLEN-1:0] csr2emu_mscratch;
wire [`ysyx_040450_XLEN-1:0] csr2emu_mcause  ;
wire [`ysyx_040450_XLEN-1:0] csr2emu_mip     ;
wire [`ysyx_040450_XLEN-1:0] csr2emu_mie     ;

always @(negedge clk) begin
    if (!resetn) begin
        {cmt_wen_r, cmt_wdest_r, cmt_wdata_r, cmt_pc_r, cmt_inst_r, cmt_valid_r} <= 0;
    end
    else /*if (~trap)*/ begin
      diff_intrNO_r      <= diff_intrNO     ;
      diff_exceptionPC_r <= diff_exceptionPC;
      cmt_valid_r <= cmt_valid;
      cmt_pc_r    <= cmt_pc   ;
      cmt_inst_r  <= cmt_inst ;
      cmt_skip_r  <= cmt_skip ;
      cmt_wen_r   <= cmt_wen  ;
      cmt_wdest_r <= cmt_wdest;
      cmt_wdata_r <= cmt_wdata;
      regs_diff   <= rf_regs;
      
      if(inst_0x7b & cmt_valid) begin
        $write("%c",regs_diff[10]);
      end
    end
end
reg [`ysyx_040450_csr2emu_BUS_WD-1:0] csr2emu_bus_d1,csr2emu_bus_d2;
always @(posedge clk)begin
  csr2emu_bus_d1 <= csr2emu_bus;
end
always @(negedge clk)begin
  csr2emu_bus_d2 <= csr2emu_bus_d1;
end
assign {
  csr2emu_mcycle  ,
  csr2emu_minstret,
  csr2emu_mstatus ,
  csr2emu_mepc    ,
  csr2emu_mtvec   ,
  csr2emu_mscratch,
  csr2emu_mcause  ,
  csr2emu_mip     ,
  csr2emu_mie     
} = csr2emu_bus;

DifftestArchEvent DifftestArchEvent(
  .clock              (clk),    // 时钟
  .coreid             (0),      // cpu id，单核时固定为0
  .intrNO             (diff_intrNO_r),      // 中断号，非零有效
  .cause              (0),      // 异常号，非零有效
  .exceptionPC        (diff_exceptionPC_r),      // 产生异常或中断时的PC
  .exceptionInst      (0)       // 产生异常时的指令，未使用
);

DifftestInstrCommit DifftestInstrCommit(
  .clock              (clk),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid_r),
  .pc                 (cmt_pc_r),
  .instr              (cmt_inst_r),
  .special            (0),
  .skip               (cmt_skip_r),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen_r  ),
  .wdest              (cmt_wdest_r),
  .wdata              (cmt_wdata_r)
);

DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clk),
  .coreid             (0),
  .gpr_0              (regs_diff[0]),
  .gpr_1              (regs_diff[1]),
  .gpr_2              (regs_diff[2]),
  .gpr_3              (regs_diff[3]),
  .gpr_4              (regs_diff[4]),
  .gpr_5              (regs_diff[5]),
  .gpr_6              (regs_diff[6]),
  .gpr_7              (regs_diff[7]),
  .gpr_8              (regs_diff[8]),
  .gpr_9              (regs_diff[9]),
  .gpr_10             (regs_diff[10]),
  .gpr_11             (regs_diff[11]),
  .gpr_12             (regs_diff[12]),
  .gpr_13             (regs_diff[13]),
  .gpr_14             (regs_diff[14]),
  .gpr_15             (regs_diff[15]),
  .gpr_16             (regs_diff[16]),
  .gpr_17             (regs_diff[17]),
  .gpr_18             (regs_diff[18]),
  .gpr_19             (regs_diff[19]),
  .gpr_20             (regs_diff[20]),
  .gpr_21             (regs_diff[21]),
  .gpr_22             (regs_diff[22]),
  .gpr_23             (regs_diff[23]),
  .gpr_24             (regs_diff[24]),
  .gpr_25             (regs_diff[25]),
  .gpr_26             (regs_diff[26]),
  .gpr_27             (regs_diff[27]),
  .gpr_28             (regs_diff[28]),
  .gpr_29             (regs_diff[29]),
  .gpr_30             (regs_diff[30]),
  .gpr_31             (regs_diff[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clk),
  .coreid             (0),
  .valid              (ebreak),
  .code               (regs_diff[10]),
  .pc                 (cmt_pc_r),
  .cycleCnt           (csr2emu_mcycle  ),
  .instrCnt           (csr2emu_minstret)
);

DifftestCSRState DifftestCSRState(
  .clock              (clk),
  .coreid             (0),
  .priviledgeMode     (3),
  .mstatus            (csr2emu_mstatus),
  .sstatus            (csr2emu_mstatus & 64'h80000003_000DE122),
  .mepc               (csr2emu_mepc),
  .sepc               (0),
  .mtval              (0),
  .stval              (0),
  .mtvec              (csr2emu_mtvec),
  .stvec              (0),
  .mcause             (csr2emu_mcause),
  .scause             (0),
  .satp               (0),
  .mip                (0),
  .mie                (csr2emu_mie),
  .mscratch           (csr2emu_mscratch),
  .sscratch           (0),
  .mideleg            (0),
  .medeleg            (0)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clk),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);
`endif
endmodule
module ysyx_040450_cache2axi_bridge(
//--------------------------------------//
// icache interface
    input         icache_rd_req    ,
    input  [ 2:0] icache_rd_type   ,
    input  [63:0] icache_rd_addr   ,
    output        icache_rd_rdy    ,
    output        icache_ret_valid ,
    output        icache_ret_last  ,
    output [63:0] icache_ret_data  ,
//--------------------------------------//
// dcache interface
    input         dcache_rd_req    ,
    input  [ 2:0] dcache_rd_type   ,
    input  [63:0] dcache_rd_addr   ,
    output        dcache_rd_rdy    ,
    output        dcache_ret_valid ,
    output        dcache_ret_last  ,
    output [63:0] dcache_ret_data  ,
    input         dcache_wr_req    ,
    input  [ 2:0] dcache_wr_type   ,
    input  [63:0] dcache_wr_addr   ,
    input  [ 7:0] dcache_wr_wstrb  ,
    input  [127:0]dcache_wr_data   ,
    output        dcache_wr_rdy    ,
    output        dcache_wr_done   ,
//--------------------------------------//
// axi inst interface
    // AXI clock and reset signal
    // input         int,
    input         aclk,
    input         aresetn,
    //read acquire
    output [3:0]  m_axi_arid,
    output [63:0] m_axi_araddr,
    output [7:0]  m_axi_arlen,
    output [2:0]  m_axi_arsize,
    output [1:0]  m_axi_arburst,
    // output [1:0]  m_axi_arlock, //不使用
    // output [3:0]  m_axi_arcache, //不使用
    // output [2:0]  m_axi_arprot, //不使用
    output        m_axi_arvalid,
    input         m_axi_arready,
    //read response
    input  [3:0]  m_axi_rid,
    input  [63:0] m_axi_rdata,
    input  [1:0]  m_axi_rresp,
    input         m_axi_rlast,
    input         m_axi_rvalid,
    output        m_axi_rready,
    //write acquire
    output [3:0]  m_axi_awid,
    output [63:0] m_axi_awaddr,
    output [7:0]  m_axi_awlen,
    output [2:0]  m_axi_awsize,
    output [1:0]  m_axi_awburst,
    // output [1:0]  m_axi_awlock, //不使用
    // output [3:0]  m_axi_awcache, //不使用
    // output [2:0]  m_axi_awprot, //不使用
    output        m_axi_awvalid,
    input         m_axi_awready,
    //write data
    output [63:0] m_axi_wdata,
    output [7:0]  m_axi_wstrb,
    output        m_axi_wlast,
    output        m_axi_wvalid,
    input         m_axi_wready,
    //write response
    input  [3:0]  m_axi_bid,
    input  [1:0]  m_axi_bresp,
    input         m_axi_bvalid,
    output        m_axi_bready
);
//--------------------------------------//
// finite state machine of read
localparam R_IDLE        = 5'b00001; // initial state
localparam R_DATA_ACCEPT = 5'b00010; // accept the acquire of data loading
localparam R_INST_ACCEPT = 5'b00100; // accept the acquire of inst fetch
localparam R_INST_RETURN = 5'b01000; // return the inst
localparam R_DATA_RETURN = 5'b10000; // return the data

reg [4:0] r_state_curr;
reg [4:0] r_state_next;

always @(posedge aclk) begin
    if(!aresetn) begin
        r_state_curr <= R_IDLE;
    end 
    else begin
        r_state_curr <= r_state_next;
    end
end

always @(*) begin
    case(r_state_curr)
        R_IDLE: begin
            // priority: load > inst fetch
            if(dcache_rd_req)begin
                r_state_next = R_DATA_ACCEPT;
            end
            else if(icache_rd_req) begin
                r_state_next = R_INST_ACCEPT;
            end
            else begin
                r_state_next = R_IDLE;
            end
        end
        R_DATA_ACCEPT: begin
            if(m_axi_arvalid && m_axi_arready) begin
                r_state_next = R_DATA_RETURN;
            end
            else begin
                r_state_next = R_DATA_ACCEPT;
            end
        end
        R_INST_ACCEPT: begin
            if(m_axi_arvalid && m_axi_arready) begin
                r_state_next = R_INST_RETURN;
            end
            else begin
                r_state_next = R_INST_ACCEPT;
            end
        end
        R_DATA_RETURN: begin
            if(m_axi_rvalid && m_axi_rready && m_axi_rlast) begin
                r_state_next = R_IDLE;
            end
            else begin
                r_state_next = R_DATA_RETURN;
            end
        end
        R_INST_RETURN: begin
            if(m_axi_rvalid && m_axi_rready && m_axi_rlast) begin
                r_state_next = R_IDLE;
            end
            else begin
                r_state_next = R_INST_RETURN;
            end
        end
        default: begin
            r_state_next = R_IDLE;
        end
    endcase
end

//--------------------------------------//
// finite state machine of write

// no matter awvalid&awready first or wvalid&wready first
// or all valid at the same time, it can handle
localparam W_IDLE        = 6'b000001;
localparam W_ACCEPT      = 6'b000010;
localparam W_ADDR_ACCEPT = 6'b000100; // awvalid&awready first
localparam W_DATA_ACCEPT = 6'b001000; // wvalid&wready first
localparam W_DATA_BURST  = 6'b010000;
localparam W_DATA_RETURN = 6'b100000;

reg [5:0] w_state_curr;
reg [5:0] w_state_next;

always @(posedge aclk) begin
    if(!aresetn) begin
        w_state_curr <= W_IDLE;
    end 
    else begin
        w_state_curr <= w_state_next;
    end
end

always @(*) begin
    case(w_state_curr)
        W_IDLE: begin
            if(dcache_wr_req)begin
                w_state_next = W_ACCEPT;
            end
            else begin
                w_state_next = W_IDLE;
            end
        end
        W_ACCEPT: begin
            if(m_axi_awvalid && m_axi_awready && m_axi_wvalid && m_axi_wready) begin
                w_state_next = m_axi_wlast ? W_DATA_RETURN : W_DATA_BURST;
            end
            else if((m_axi_awvalid && m_axi_awready) && !(m_axi_wvalid && m_axi_wready))begin
                w_state_next = W_ADDR_ACCEPT;
            end
            else if(!(m_axi_awvalid && m_axi_awready) && (m_axi_wvalid && m_axi_wready))begin
                w_state_next = W_DATA_ACCEPT;
            end
            else begin
                w_state_next = W_ACCEPT;
            end
        end
        W_ADDR_ACCEPT: begin
            if(m_axi_wvalid && m_axi_wready) begin
                w_state_next = m_axi_wlast ? W_DATA_RETURN : W_DATA_BURST;
            end
            else begin
                w_state_next = W_ADDR_ACCEPT;
            end
        end
        W_DATA_ACCEPT: begin
            if(m_axi_awvalid && m_axi_awready) begin
                w_state_next = m_axi_wlast ? W_DATA_RETURN : W_DATA_BURST;
            end
            else begin
                w_state_next = W_DATA_ACCEPT;
            end
        end
        W_DATA_BURST: begin
            if(m_axi_wvalid && m_axi_wready && m_axi_wlast) begin
                w_state_next = W_DATA_RETURN;
            end
            else begin
                w_state_next = W_DATA_BURST;
            end
        end
        W_DATA_RETURN: begin
            if(m_axi_bvalid && m_axi_bready) begin
                w_state_next = W_IDLE;
            end
            else begin
                w_state_next = W_DATA_RETURN;
            end
        end
        default: begin
            w_state_next = W_IDLE;
        end
    endcase
end

//--------------------------------------//
//read acquire
assign m_axi_arlen = (r_state_curr == R_DATA_ACCEPT) ? {7'b0,dcache_rd_type[2]} : {7'b0,icache_rd_type[2]};
assign m_axi_arburst = 2'b01; // INCR
// assign m_axi_arlock = 2'b0;
// assign m_axi_arcache = 4'b0;
// assign m_axi_arprot = 3'b0;

// once arvalid rise, they can NOT be changed !!!
assign m_axi_arvalid = (r_state_curr == R_DATA_ACCEPT || r_state_curr == R_INST_ACCEPT) ? 1'b1 : 1'b0;
assign m_axi_arid    = (r_state_curr == R_DATA_ACCEPT) ? 4'b1 : 4'b0;
assign m_axi_araddr  = (r_state_curr == R_DATA_ACCEPT) ? dcache_rd_addr : icache_rd_addr;
assign m_axi_arsize  = (r_state_curr == R_DATA_ACCEPT) ? {1'b0,dcache_rd_type[1:0]} : {1'b0,icache_rd_type[1:0]};

assign icache_rd_rdy = (m_axi_arvalid && m_axi_arready && m_axi_arid==4'b0)? 1'b1 : 1'b0;
// assign inst_sram_addr_ok = (arvalid && arready && arid==4'b0)? 1'b1 : 1'b0;

assign dcache_rd_rdy = (m_axi_arvalid && m_axi_arready && m_axi_arid==4'b1)? 1'b1 : 1'b0;
// assign data_sram_addr_ok = ((arvalid && arready && arid==4'b1) ||
//                            (w_state_curr == W_DATA_ACCEPT && awvalid && awready) || 
//                            (w_state_curr == W_ADDR_ACCEPT && wvalid  && wready ) ||
//                            (w_state_curr == W_ACCEPT && awvalid && awready && wvalid && wready)) ?
//                             1'b1 : 1'b0;

//--------------------------------------//
//read response
assign m_axi_rready = (r_state_curr == R_DATA_RETURN || r_state_curr == R_INST_RETURN) ? 1'b1: 1'b0;

assign {icache_ret_data, dcache_ret_data} = {2{m_axi_rdata}};

assign icache_ret_valid = (m_axi_rvalid && m_axi_rready && m_axi_rid==4'b0)? 1'b1 : 1'b0;
assign icache_ret_last = icache_ret_valid && m_axi_rlast;
// assign inst_sram_data_ok = (rvalid && rready && rid==4'b0)? 1'b1 : 1'b0;

assign dcache_ret_valid = (m_axi_rvalid && m_axi_rready && m_axi_rid==4'b1)? 1'b1 : 1'b0;
assign dcache_ret_last  = dcache_ret_valid && m_axi_rlast;
assign dcache_wr_done   = (m_axi_bvalid && m_axi_bready && m_axi_bid==4'b1) ? 1'b1 : 1'b0;
// assign data_sram_data_ok = ((rvalid && rready && rid==4'b1) ||
//                            (bvalid && bready && bid==4'b1)) ?
//                            1'b1 : 1'b0;

//--------------------------------------//
//write acquire
// assign m_axi_awlen = {7'b0,{dcache_wr_type[2]}};
assign m_axi_awburst = 2'b01;
// assign m_axi_awlock = 2'b0;
// assign m_axi_awcache = 4'b0;
// assign m_axi_awprot = 3'b0;
assign m_axi_awvalid = (w_state_curr == W_ACCEPT || w_state_curr == W_DATA_ACCEPT)? 1'b1 : 1'b0;

reg [3 :0] awid_r;
reg [ 7:0] awlen_r;
reg [2 :0] awsize_r;
reg [63:0] awaddr_r;
// in order to save the value of signals
// once awvalid rise, they can NOT be changed
always @(posedge aclk) begin
    if(!aresetn)begin
        awid_r <= 4'b0;
        awlen_r <= 8'b0;
        awsize_r <= 3'b0;
        awaddr_r <= 64'b0;
    end
    else if (dcache_wr_req) begin
        awid_r <= 4'b1;
        awlen_r <= {7'b0,dcache_wr_type[2]};
        awsize_r <= {1'b0,dcache_wr_type[1:0]};
        awaddr_r <= dcache_wr_addr;
    end
    else if(m_axi_bvalid && m_axi_bready) begin // FIXME 可删
        awid_r <= 4'b0;
        awlen_r <= 8'b0;
        awsize_r <= 3'b0;
        awaddr_r <= 64'b0;
    end
    else begin
        awid_r <= awid_r;
        awlen_r <= awlen_r;
        awsize_r <= awsize_r;
        awaddr_r <= awaddr_r;
    end
end

assign m_axi_awid = awid_r;
assign m_axi_awlen = awlen_r;
assign m_axi_awaddr = awaddr_r;
assign m_axi_awsize = awsize_r;

assign dcache_wr_rdy = (w_state_curr == W_IDLE) ? 1'b1/*m_axi_awready*/ : 1'b0;

//--------------------------------------//
//write data
reg [2:0] wr_cnt; //max=1
always @(posedge aclk)begin 
    if(w_state_curr==W_IDLE)begin 
        wr_cnt <= 3'b0;
    end 
    else if(m_axi_wvalid && m_axi_wready)begin
        wr_cnt <= wr_cnt + 3'b1;
    end 
    else
        wr_cnt <= wr_cnt;
end 
assign m_axi_wlast = (m_axi_awlen == {5'b0,wr_cnt});
assign m_axi_wvalid = (w_state_curr == W_ACCEPT 
                    || w_state_curr == W_ADDR_ACCEPT 
                    || w_state_curr == W_DATA_BURST) ? 1'b1 : 1'b0;
// in order to save the value of signals
// once wvalid rise, they can NOT be changed
reg [127:0] wdata_r;
reg [7:0] wstrb_r;

always @(posedge aclk) begin
    if(!aresetn)begin
        wdata_r <= 128'b0;
        wstrb_r <= 8'b0;
    end
    else if (dcache_wr_req) begin
        wdata_r <= dcache_wr_data;
        wstrb_r <= dcache_wr_wstrb;
    end
    else if (m_axi_bvalid && m_axi_bready) begin
        wdata_r <= 128'b0;
        wstrb_r <= 8'b0;
    end
    else begin
        wdata_r <= wdata_r;
        wstrb_r <= wstrb_r;
    end
end

assign m_axi_wdata = wr_cnt[0] ? wdata_r[127:64] : wdata_r[63:0];
assign m_axi_wstrb = wstrb_r;

//--------------------------------------//
//write response
assign m_axi_bready = (w_state_curr == W_DATA_RETURN) ? 1'b1 : 1'b0;

endmodule

module ysyx_040450_cpu(
    input         clk,
    input         resetn,
    // inst sram interface
    output        cpu_inst_req    ,
    output        cpu_inst_wr     ,
    output [1 :0] cpu_inst_size   ,
    output [7 :0] cpu_inst_wstrb  ,
    output [63:0] cpu_inst_addr   ,
    output [63:0] cpu_inst_wdata  ,
    input         cpu_inst_addr_ok,
    input         cpu_inst_data_ok,
    input  [63:0] cpu_inst_rdata  ,
    // data sram interface
    output        cpu_data_req    ,
    output        cpu_data_wr     ,
    output [1 :0] cpu_data_size   ,
    output [7 :0] cpu_data_wstrb  ,
    output [63:0] cpu_data_addr   ,
    output [63:0] cpu_data_wdata  ,
    input         cpu_data_addr_ok,
    input         cpu_data_data_ok,
    input  [63:0] cpu_data_rdata  ,
    `ifdef ysyx_040450_ZEMU_DIFF
    //trace debug interface
    output [`ysyx_040450_DBG_WB_BUS_WD   -1:0]  debug_wb_bus  ,
    `endif
    output fencei_req,
    input  fencei_ack
);

wire        data_sram_req    ;
wire        data_sram_wr     ;
wire [1 :0] data_sram_size   ;
wire [7 :0] data_sram_wstrb  ;
wire [63:0] data_sram_addr   ;
wire [63:0] data_sram_wdata  ;
wire        data_sram_addr_ok;
wire        data_sram_data_ok;
wire [63:0] data_sram_rdata  ;

wire        clint_data_req    ;
wire        clint_data_wr     ;
wire [1 :0] clint_data_size   ;
wire [7 :0] clint_data_wstrb  ;
wire [63:0] clint_data_addr   ;
wire [63:0] clint_data_wdata  ;
wire        clint_data_addr_ok;
wire        clint_data_data_ok;
wire [63:0] clint_data_rdata  ;

wire clint_sft_irq;
wire clint_tmr_irq;

// 1x2 bridge
ysyx_040450_cpu_biu u_cpu_biu(
    .data_sram_req    (data_sram_req    ),
    .data_sram_wr     (data_sram_wr     ),
    .data_sram_size   (data_sram_size   ),
    .data_sram_wstrb  (data_sram_wstrb  ),
    .data_sram_addr   (data_sram_addr   ),
    .data_sram_wdata  (data_sram_wdata  ),
    .data_sram_addr_ok(data_sram_addr_ok),
    .data_sram_data_ok(data_sram_data_ok),
    .data_sram_rdata  (data_sram_rdata  ),
    .cpu_data_req    (cpu_data_req    ),
    .cpu_data_wr     (cpu_data_wr     ),
    .cpu_data_size   (cpu_data_size   ),
    .cpu_data_wstrb  (cpu_data_wstrb  ),
    .cpu_data_addr   (cpu_data_addr   ),
    .cpu_data_wdata  (cpu_data_wdata  ),
    .cpu_data_addr_ok(cpu_data_addr_ok),
    .cpu_data_data_ok(cpu_data_data_ok),
    .cpu_data_rdata  (cpu_data_rdata  ),
    .clint_data_req    (clint_data_req    ),
    .clint_data_wr     (clint_data_wr     ),
    .clint_data_size   (clint_data_size   ),
    .clint_data_wstrb  (clint_data_wstrb  ),
    .clint_data_addr   (clint_data_addr   ),
    .clint_data_wdata  (clint_data_wdata  ),
    .clint_data_addr_ok(clint_data_addr_ok),
    .clint_data_data_ok(clint_data_data_ok),
    .clint_data_rdata  (clint_data_rdata  ), 

    .clk  (clk   ),
    .rst_n(resetn)
);

ysyx_040450_clint_wrap u_clint_wrap(
    .clint_data_req    (clint_data_req    ),
    .clint_data_wr     (clint_data_wr     ),
    .clint_data_size   (clint_data_size   ),
    .clint_data_wstrb  (clint_data_wstrb  ),
    .clint_data_addr   (clint_data_addr   ),
    .clint_data_wdata  (clint_data_wdata  ),
    .clint_data_addr_ok(clint_data_addr_ok),
    .clint_data_data_ok(clint_data_data_ok),
    .clint_data_rdata  (clint_data_rdata  ),

    .clint_sft_irq(clint_sft_irq),
    .clint_tmr_irq(clint_tmr_irq),

    .clk  (clk   ),
    .rst_n(resetn)
);

ysyx_040450_core u_core(
    .clk              (clk   ),
    .resetn           (resetn),  //low active

    .inst_sram_req    (cpu_inst_req    ),
    .inst_sram_wr     (cpu_inst_wr     ),
    .inst_sram_size   (cpu_inst_size   ),
    .inst_sram_wstrb  (cpu_inst_wstrb  ),
    .inst_sram_addr   (cpu_inst_addr   ),
    .inst_sram_wdata  (cpu_inst_wdata  ),
    .inst_sram_addr_ok(cpu_inst_addr_ok),
    .inst_sram_data_ok(cpu_inst_data_ok),
    .inst_sram_rdata  (cpu_inst_rdata  ),
    
    .data_sram_req    (data_sram_req    ),
    .data_sram_wr     (data_sram_wr     ),
    .data_sram_size   (data_sram_size   ),
    .data_sram_wstrb  (data_sram_wstrb  ),
    .data_sram_addr   (data_sram_addr   ),
    .data_sram_wdata  (data_sram_wdata  ),
    .data_sram_addr_ok(data_sram_addr_ok),
    .data_sram_data_ok(data_sram_data_ok),
    .data_sram_rdata  (data_sram_rdata  ),
    
    .plic_ext_irq (1'b0),
    .clint_sft_irq(clint_sft_irq),
    .clint_tmr_irq(clint_tmr_irq),
 
    `ifdef ysyx_040450_ZEMU_DIFF
    .debug_wb_bus(debug_wb_bus),
    `endif

    .fencei_req(fencei_req),
    .fencei_ack(fencei_ack)
);

endmodule

module ysyx_040450(
  input                               clock,
  input                               reset,
  input         io_interrupt,

  input         io_master_awready,
  output        io_master_awvalid,
  output [31:0] io_master_awaddr,
  output [3:0]  io_master_awid,
  output [7:0]  io_master_awlen,
  output [2:0]  io_master_awsize,
  output [1:0]  io_master_awburst,
  input         io_master_wready,
  output        io_master_wvalid,
  output [63:0] io_master_wdata,
  output [7:0]  io_master_wstrb,
  output        io_master_wlast,
  output        io_master_bready,
  input         io_master_bvalid,
  input  [1:0]  io_master_bresp,
  input  [3:0]  io_master_bid,
  input         io_master_arready,
  output        io_master_arvalid,
  output [31:0] io_master_araddr,
  output [3:0]  io_master_arid,
  output [7:0]  io_master_arlen,
  output [2:0]  io_master_arsize,
  output [1:0]  io_master_arburst,
  output        io_master_rready,
  input         io_master_rvalid,
  input  [1:0]  io_master_rresp,
  input  [63:0] io_master_rdata,
  input         io_master_rlast,
  input  [3:0]  io_master_rid,

  output        io_slave_awready,
  input         io_slave_awvalid,
  input  [31:0] io_slave_awaddr,
  input  [3:0]  io_slave_awid,
  input  [7:0]  io_slave_awlen,
  input  [2:0]  io_slave_awsize,
  input  [1:0]  io_slave_awburst,
  output        io_slave_wready,
  input         io_slave_wvalid,
  input  [63:0] io_slave_wdata,
  input  [7:0]  io_slave_wstrb,
  input         io_slave_wlast,
  input         io_slave_bready,
  output        io_slave_bvalid,
  output [1:0]  io_slave_bresp,
  output [3:0]  io_slave_bid,
  output        io_slave_arready,
  input         io_slave_arvalid,
  input  [31:0] io_slave_araddr,
  input  [3:0]  io_slave_arid,
  input  [7:0]  io_slave_arlen,
  input  [2:0]  io_slave_arsize,
  input  [1:0]  io_slave_arburst,
  input         io_slave_rready,
  output        io_slave_rvalid,
  output [1:0]  io_slave_rresp,
  output [63:0] io_slave_rdata,
  output        io_slave_rlast,
  output [3:0]  io_slave_rid,


  output   [5:0] io_sram0_addr    ,
  output         io_sram0_cen     ,
  output         io_sram0_wen     ,
  output [127:0] io_sram0_wmask   ,
  output [127:0] io_sram0_wdata   ,
  input  [127:0] io_sram0_rdata   ,
  output   [5:0] io_sram1_addr    ,
  output         io_sram1_cen     ,
  output         io_sram1_wen     ,
  output [127:0] io_sram1_wmask   ,
  output [127:0] io_sram1_wdata   ,
  input  [127:0] io_sram1_rdata   ,
  output   [5:0] io_sram2_addr    ,
  output         io_sram2_cen     ,
  output         io_sram2_wen     ,
  output [127:0] io_sram2_wmask   ,
  output [127:0] io_sram2_wdata   ,
  input  [127:0] io_sram2_rdata   ,
  output   [5:0] io_sram3_addr    ,
  output         io_sram3_cen     ,
  output         io_sram3_wen     ,
  output [127:0] io_sram3_wmask   ,
  output [127:0] io_sram3_wdata   ,
  input  [127:0] io_sram3_rdata   ,
  output   [5:0] io_sram4_addr    ,
  output         io_sram4_cen     ,
  output         io_sram4_wen     ,
  output [127:0] io_sram4_wmask   ,
  output [127:0] io_sram4_wdata   ,
  input  [127:0] io_sram4_rdata   ,
  output   [5:0] io_sram5_addr    ,
  output         io_sram5_cen     ,
  output         io_sram5_wen     ,
  output [127:0] io_sram5_wmask   ,
  output [127:0] io_sram5_wdata   ,
  input  [127:0] io_sram5_rdata   ,
  output   [5:0] io_sram6_addr    ,
  output         io_sram6_cen     ,
  output         io_sram6_wen     ,
  output [127:0] io_sram6_wmask   ,
  output [127:0] io_sram6_wdata   ,
  input  [127:0] io_sram6_rdata   ,
  output   [5:0] io_sram7_addr    ,
  output         io_sram7_cen     ,
  output         io_sram7_wen     ,
  output [127:0] io_sram7_wmask   ,
  output [127:0] io_sram7_wdata   ,
  input  [127:0] io_sram7_rdata   
);
wire [63:0] m_axi_awaddr;
wire [63:0] m_axi_araddr;

wire cpu_resetn = ~reset;
//cpu inst sram
wire        cpu_inst_req;
wire        cpu_inst_wr;
wire [1 :0] cpu_inst_size;
wire [7 :0] cpu_inst_wstrb;
wire [63:0] cpu_inst_addr;
wire [63:0] cpu_inst_wdata;
wire        cpu_inst_addr_ok;
wire        cpu_inst_data_ok;
wire [63:0] cpu_inst_rdata;
//cpu data sram
wire        cpu_data_req;
wire        cpu_data_wr;
wire [1 :0] cpu_data_size;
wire [7 :0] cpu_data_wstrb;
wire [63:0] cpu_data_addr;
wire [63:0] cpu_data_wdata;
wire        cpu_data_addr_ok;
wire        cpu_data_data_ok;
wire [63:0] cpu_data_rdata;
//cache interface
wire        icache_rd_req   ;
wire [ 2:0] icache_rd_type  ;
wire [63:0] icache_rd_addr  ;
wire        icache_rd_rdy   ;
wire        icache_ret_valid;
wire        icache_ret_last ;
wire [63:0] icache_ret_data ;
wire        dcache_rd_req   ;
wire [ 2:0] dcache_rd_type  ;
wire [63:0] dcache_rd_addr  ;
wire        dcache_rd_rdy   ;
wire        dcache_ret_valid;
wire        dcache_ret_last ;
wire [63:0] dcache_ret_data ;
wire        dcache_wr_req   ;
wire [ 2:0] dcache_wr_type  ;
wire [63:0] dcache_wr_addr  ;
wire [ 7:0] dcache_wr_wstrb ;
wire [127:0]dcache_wr_data  ;
wire        dcache_wr_rdy   ;
wire        dcache_wr_done  ;
//cache sync
wire fencei_req;
wire fencei_ack;
wire         sync_rvld    ; // 读请求
wire         sync_rrdy    ; // 读应答
wire         sync_rdata_ok; // 数据有效
wire [  6:0] sync_rindex  ; // $line index
wire [ 43:0] sync_rinfos  ; // tag v d 23bx2
wire [255:0] sync_rdatas  ; // 两路数据
wire         sync_wvld  ; // 写请求
wire         sync_wrdy  ; // 写应答
wire [  6:0] sync_windex; // $line index
wire [ 43:0] sync_wtagvs; // tag v 22bx2
wire [255:0] sync_wdatas; // 两路数据

ysyx_040450_cache2axi_bridge i_cache2axi_bridge(
  .icache_rd_req   (icache_rd_req   ),
  .icache_rd_type  (icache_rd_type  ),
  .icache_rd_addr  (icache_rd_addr  ),
  .icache_rd_rdy   (icache_rd_rdy   ),
  .icache_ret_valid(icache_ret_valid),
  .icache_ret_last (icache_ret_last ),
  .icache_ret_data (icache_ret_data ),
  .dcache_rd_req   (dcache_rd_req   ),
  .dcache_rd_type  (dcache_rd_type  ),
  .dcache_rd_addr  (dcache_rd_addr  ),
  .dcache_rd_rdy   (dcache_rd_rdy   ),
  .dcache_ret_valid(dcache_ret_valid),
  .dcache_ret_last (dcache_ret_last ),
  .dcache_ret_data (dcache_ret_data ),
  .dcache_wr_req   (dcache_wr_req   ),
  .dcache_wr_type  (dcache_wr_type  ),
  .dcache_wr_addr  (dcache_wr_addr  ),
  .dcache_wr_wstrb (dcache_wr_wstrb ),
  .dcache_wr_data  (dcache_wr_data  ),
  .dcache_wr_rdy   (dcache_wr_rdy   ),
  .dcache_wr_done  (dcache_wr_done  ),
  .m_axi_arid   (io_master_arid   ),
  .m_axi_araddr (m_axi_araddr     ),
  .m_axi_arlen  (io_master_arlen  ),
  .m_axi_arsize (io_master_arsize ),
  .m_axi_arburst(io_master_arburst),
  // .m_axi_arlock (),
  // .m_axi_arcache(),
  // .m_axi_arprot (),
  .m_axi_arvalid(io_master_arvalid),
  .m_axi_arready(io_master_arready),
  .m_axi_rid   (io_master_rid     ),
  .m_axi_rdata (io_master_rdata   ),
  .m_axi_rresp (io_master_rresp   ),
  .m_axi_rlast (io_master_rlast   ),
  .m_axi_rvalid(io_master_rvalid  ),
  .m_axi_rready(io_master_rready  ),
  .m_axi_awid   (io_master_awid   ),
  .m_axi_awaddr (m_axi_awaddr     ),
  .m_axi_awlen  (io_master_awlen  ),
  .m_axi_awsize (io_master_awsize ),
  .m_axi_awburst(io_master_awburst),
  // .m_axi_awlock (),
  // .m_axi_awcache(),
  // .m_axi_awprot (),
  .m_axi_awvalid(io_master_awvalid),
  .m_axi_awready(io_master_awready),
  .m_axi_wdata (io_master_wdata ),
  .m_axi_wstrb (io_master_wstrb ),
  .m_axi_wlast (io_master_wlast ),
  .m_axi_wvalid(io_master_wvalid),
  .m_axi_wready(io_master_wready),
  .m_axi_bid   (io_master_bid   ),
  .m_axi_bresp (io_master_bresp ),
  .m_axi_bvalid(io_master_bvalid),
  .m_axi_bready(io_master_bready),
  .aclk(clock),
  .aresetn(cpu_resetn)
);

assign io_master_awaddr = m_axi_awaddr[31:0];
assign io_master_araddr = m_axi_araddr[31:0];

ysyx_040450_cache_sync_bridge cache_sync_bridge(
  .fencei_req(fencei_req),
  .fencei_ack(fencei_ack),
  .sync_rvld    (sync_rvld    ),
  .sync_rrdy    (sync_rrdy    ),
  .sync_rdata_ok(sync_rdata_ok),
  .sync_rindex  (sync_rindex  ),
  .sync_rinfos  (sync_rinfos  ),
  .sync_rdatas  (sync_rdatas  ),
  .sync_wvld  (sync_wvld  ),
  .sync_wrdy  (sync_wrdy  ),
  .sync_windex(sync_windex),
  .sync_wtagvs(sync_wtagvs),
  .sync_wdatas(sync_wdatas),
  .clk      (clock),
  .resetn   (cpu_resetn)
);

ysyx_040450_icache u_icache(
  .cpu_sram_req    (cpu_inst_req),
  .cpu_sram_wr     (cpu_inst_wr),
  .cpu_sram_size   (cpu_inst_size),
  .cpu_sram_wstrb  (cpu_inst_wstrb),
  .cpu_sram_addr   (cpu_inst_addr),
  .cpu_sram_wdata  (cpu_inst_wdata),
  .cpu_sram_addr_ok(cpu_inst_addr_ok),
  .cpu_sram_data_ok(cpu_inst_data_ok),
  .cpu_sram_rdata  (cpu_inst_rdata),

  .sync_wvld  (sync_wvld  ),
  .sync_wrdy  (sync_wrdy  ),
  .sync_windex(sync_windex),
  .sync_wtagvs(sync_wtagvs),
  .sync_wdatas(sync_wdatas),
  
  .icache_rd_req   (icache_rd_req   ),
  .icache_rd_type  (icache_rd_type  ),
  .icache_rd_addr  (icache_rd_addr  ),
  .icache_rd_rdy   (icache_rd_rdy   ),
  .icache_ret_valid(icache_ret_valid),
  .icache_ret_last (icache_ret_last ),
  .icache_ret_data (icache_ret_data ),

  .io_sram0_addr (io_sram0_addr ),
  .io_sram0_cen  (io_sram0_cen  ),
  .io_sram0_wen  (io_sram0_wen  ),
  .io_sram0_wmask(io_sram0_wmask),
  .io_sram0_wdata(io_sram0_wdata),
  .io_sram0_rdata(io_sram0_rdata),
  .io_sram1_addr (io_sram1_addr ),
  .io_sram1_cen  (io_sram1_cen  ),
  .io_sram1_wen  (io_sram1_wen  ),
  .io_sram1_wmask(io_sram1_wmask),
  .io_sram1_wdata(io_sram1_wdata),
  .io_sram1_rdata(io_sram1_rdata),
  .io_sram2_addr (io_sram2_addr ),
  .io_sram2_cen  (io_sram2_cen  ),
  .io_sram2_wen  (io_sram2_wen  ),
  .io_sram2_wmask(io_sram2_wmask),
  .io_sram2_wdata(io_sram2_wdata),
  .io_sram2_rdata(io_sram2_rdata),
  .io_sram3_addr (io_sram3_addr ),
  .io_sram3_cen  (io_sram3_cen  ),
  .io_sram3_wen  (io_sram3_wen  ),
  .io_sram3_wmask(io_sram3_wmask),
  .io_sram3_wdata(io_sram3_wdata),
  .io_sram3_rdata(io_sram3_rdata),
  .clk      (clock),
  .resetn   (cpu_resetn)
);

ysyx_040450_dcache u_dcache(
  .cpu_sram_req      (cpu_data_req),
  .cpu_sram_wr       (cpu_data_wr),
  .cpu_sram_size     (cpu_data_size),
  .cpu_sram_wstrb    (cpu_data_wstrb),
  .cpu_sram_addr     (cpu_data_addr),
  .cpu_sram_wdata    (cpu_data_wdata),
  .cpu_sram_addr_ok  (cpu_data_addr_ok),
  .cpu_sram_data_ok  (cpu_data_data_ok),
  .cpu_sram_rdata    (cpu_data_rdata),

  .sync_rvld    (sync_rvld    ),
  .sync_rrdy    (sync_rrdy    ),
  .sync_rdata_ok(sync_rdata_ok),
  .sync_rindex  (sync_rindex  ),
  .sync_rinfos  (sync_rinfos  ),
  .sync_rdatas  (sync_rdatas  ),

  .dcache_rd_req   (dcache_rd_req   ),
  .dcache_rd_type  (dcache_rd_type  ),
  .dcache_rd_addr  (dcache_rd_addr  ),
  .dcache_rd_rdy   (dcache_rd_rdy   ),
  .dcache_ret_valid(dcache_ret_valid),
  .dcache_ret_last (dcache_ret_last ),
  .dcache_ret_data (dcache_ret_data ),
  .dcache_wr_req   (dcache_wr_req   ),
  .dcache_wr_type  (dcache_wr_type  ),
  .dcache_wr_addr  (dcache_wr_addr  ),
  .dcache_wr_wstrb (dcache_wr_wstrb ),
  .dcache_wr_data  (dcache_wr_data  ),
  .dcache_wr_rdy   (dcache_wr_rdy   ),
  .dcache_wr_done  (dcache_wr_done  ),

  .io_sram0_addr (io_sram4_addr ),
  .io_sram0_cen  (io_sram4_cen  ),
  .io_sram0_wen  (io_sram4_wen  ),
  .io_sram0_wmask(io_sram4_wmask),
  .io_sram0_wdata(io_sram4_wdata),
  .io_sram0_rdata(io_sram4_rdata),
  .io_sram1_addr (io_sram5_addr ),
  .io_sram1_cen  (io_sram5_cen  ),
  .io_sram1_wen  (io_sram5_wen  ),
  .io_sram1_wmask(io_sram5_wmask),
  .io_sram1_wdata(io_sram5_wdata),
  .io_sram1_rdata(io_sram5_rdata),
  .io_sram2_addr (io_sram6_addr ),
  .io_sram2_cen  (io_sram6_cen  ),
  .io_sram2_wen  (io_sram6_wen  ),
  .io_sram2_wmask(io_sram6_wmask),
  .io_sram2_wdata(io_sram6_wdata),
  .io_sram2_rdata(io_sram6_rdata),
  .io_sram3_addr (io_sram7_addr ),
  .io_sram3_cen  (io_sram7_cen  ),
  .io_sram3_wen  (io_sram7_wen  ),
  .io_sram3_wmask(io_sram7_wmask),
  .io_sram3_wdata(io_sram7_wdata),
  .io_sram3_rdata(io_sram7_rdata),
  .clk      (clock),
  .resetn   (cpu_resetn)
);

// CPU核
ysyx_040450_cpu u_ysyx_22040450_cpu(
    .cpu_inst_req    (cpu_inst_req    ),
    .cpu_inst_wr     (cpu_inst_wr     ),
    .cpu_inst_size   (cpu_inst_size   ),
    .cpu_inst_wstrb  (cpu_inst_wstrb  ),
    .cpu_inst_addr   (cpu_inst_addr   ),
    .cpu_inst_wdata  (cpu_inst_wdata  ),
    .cpu_inst_addr_ok(cpu_inst_addr_ok),
    .cpu_inst_data_ok(cpu_inst_data_ok),
    .cpu_inst_rdata  (cpu_inst_rdata  ),
    
    .cpu_data_req    (cpu_data_req    ),
    .cpu_data_wr     (cpu_data_wr     ),
    .cpu_data_size   (cpu_data_size   ),
    .cpu_data_wstrb  (cpu_data_wstrb  ),
    .cpu_data_addr   (cpu_data_addr   ),
    .cpu_data_wdata  (cpu_data_wdata  ),
    .cpu_data_addr_ok(cpu_data_addr_ok),
    .cpu_data_data_ok(cpu_data_data_ok),
    .cpu_data_rdata  (cpu_data_rdata  ),

    .fencei_req(fencei_req),
    .fencei_ack(fencei_ack),
    .clk   (clock   ),
    .resetn(cpu_resetn)  //low active
);

// io_slave 处理
assign io_slave_awready = 0;
assign io_slave_wready = 0;
assign io_slave_bvalid = 0;
assign io_slave_bresp = 0;
assign io_slave_bid = 0;
assign io_slave_arready = 0;
assign io_slave_rvalid = 0;
assign io_slave_rresp = 0;
assign io_slave_rdata = 0;
assign io_slave_rlast = 0;
assign io_slave_rid = 0;

// wire _unused_ok = &{1'b0,
//   io_logCtrl_log_begin,
//   io_logCtrl_log_end,
//   io_logCtrl_log_level,
//   io_perfInfo_clean,
//   io_perfInfo_dump,
//   io_uart_in_ch,
//   1'b0};

endmodule
